开发日志:2022.11问题汇总-Qt自带的阴影类、跨线程问题汇总、hover相关、全屏轮子,一些思考。

2022/11/07 开发日志 共 4467 字,约 13 分钟

一点思考:故事的结局重不重要?

我语文不好,但是我数学不好。

我数学不好,但是我英语不好。

我英语不好,但是我物理不好。

我物理不好,但是我化学不好。

我化学不好,但是我历史不好。

我历史不好,但是我政治不好。

我政治不好,但是我地理不好。

我地理不好,但是我生物不好。

我生物不好,但是我美术不好。

我美术不好,但是我体育不好。

此生什么都不好,来世什么都不好。


故事的结局重不重要?之前看到这个辩题,也看了那场精彩的辩论,不得不说名校出来的辩手确实能在短时间内就组织出一套完整的观点和话术来动摇对方的论点,但我觉得这道题实在出的不好。

故事的结局重要吗?诚然,如果一个绝好的故事,却以一个烂透了的结局结束,若以人生做比,一段无疾而终的恋爱,一段没有终点的旅程,一场没有屠龙的终点,一局没有boss的游戏,这些词组合在一起光是看上去就让人充满了遗憾,但即使没有终点,回头望去,一路的艰难险阻,风光正好都在向我们证明这段旅途存在。

当我看到这道辩题的时候我下意识的认为故事的结局不重要,我是一个非常在乎过程的人。我一直觉得对于我来说结局痛苦与否并不重要,因为人世间痛苦与快乐本就分不太清,我只求它货真价实。

去年的那次分手,我没有特别悲伤,那天我站在风里想了很久很久,总是不自觉地拿起手机看时间,假装会有人来给我发消息。其实我知道是不会有的,但是我不觉得痛苦,好像还是那样该吃吃该喝喝,只是感觉心里突然少了什么感情,像是突然少了一块,空落落的,并不疼。

后来我把“等有钱了一起去做”的todo list上的事自己一个人做了一遍,去看风力发电机,去看了海,去看了日出,去买了保险,去深夜的操场上裸奔…但是我都没有感觉,就好像这一切是生活里非常稀疏平常的一件事。心情非常麻木,心里并没有什么感到痛苦的地方。我觉得自己已经爱够了,该爱的都爱过了,再多就不礼貌了。

再到后来我打包把和你有关的东西准备扔掉的时候,从你给我的礼物掉出一封信。我想起在一起的那天,你双手紧抓着一封信,哭的像个小孩儿,说你很想和我在一起。那天我没有感觉,我就喝酒,喝了好多好多酒,喝到吐的时候终于哭出来了。就这么鼻涕混着眼泪昏喝了半年,我才发现原来故事的结局如此重要。

最近看了个视频,电子竞技,结局重不重要,看完真的意难平,就小森ence警亭那枪,他花了两年去反省,你说结局重要吗?

原来,一个好的结局可以感动别人,一个坏的结局只能感动自己,大抵如此吧。

一些笔记

1.qt中,自带的阴影控件使用:

上代码:

  QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(this);
  // 阴影偏移
  shadowEffect->setOffset(0, 0);
  // 阴影颜色;
  shadowEffect->setColor(Qt::black);
  // 阴影半径;
  shadowEffect->setBlurRadius(15);
  // 给窗口设置上当前的阴影效果;
  this->ui.wid_bg->setGraphicsEffect(shadowEffect);

这段代码就是给一个窗口的周边加上阴影的,但是需要注意的一点是,这个阴影需要保证这个窗口的边上是可见的,也就是说这个窗口,也就是说这个ui.wid_bg是需要嵌套在this内的,总之要保证这个窗口的周围可见,否则这个阴影可能就会出问题。

另外需要注意的一点是,如果这个阴影只是一个单纯的分层,请不要设置这个窗口的透明度

image

比如这样,你就需要设置wid_bg为透明的,但是不能设置wid_cam为透明的,因为wid_cam的透明度会直接影响到阴影的深度。

2.跨线程问题相关

哎,搞了半天,又讲回跨线程问题了。讲道理我其实是比较想学着做服务器这块的,但是为什么qt这个….跨线程也太容易出问题了,而且错误了也没有相应的提示..

回到整体,跨线程有几个小问题

1.connect的第五个参数

先说在前面,就是qt的控件都是不支持跨线程调用的,所以说qt的所有跨线程调用控件实际上都是非法的(?),所以在跨线程调用控件的时候,是有可能出错的,如果两个线程同时抢一个控件,就会直接崩溃掉。

虽然说qt 的 connect函数有第五个参数 Qt::ConnectionType,但是这个默认参数我感觉是不可信的,所以需要自己设定一下,也就是在涉及跨线程调用处,都使用上信号槽机制,同时修改一下第五个参数。

跨线程调用设置参数为Qt::QueuedConnection就行,槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。一般不用Qt::BlockingQueuedConnection,这个是槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。但是这个多少容易沾点卡死了,有需要才会用。

2.互斥量mutex

在前面说了这个队列化跨线程调用的问题,虽然但是,在实际使用中又出现了另外一个问题,就是如果我现在这个节点正在被删除,但是我跨线程的函数又来操作这个节点,这种情况下要被允许运行吗?(虽然上面已经是队列化跨线程操作了,但是…哥们反正这里就是出错了,当然实际上不是这样的,具体错误要看下去)

答案肯定是否定的,这个时候这个节点不应该能够被操作,应该是要等这个节点被删除结束了,跨线程的操作才应该被允许来找节点才对,但是如果它硬要插入,这个时候就会出错了。

ok,那么问题来了,我们该怎么去做呢?这个时候就要请出我们的线程锁QMutex

这玩意用起来也简单,就是给一个指定范围的变量QMutex mutex,然后在函数开头mutex.lock(),然后mutex.unlock(),当这个mutex在lock的时候,mutex.lock()这条命令会直接阻塞整个线程

看不懂算了,回去看下操作系统,哥们真不会不懂吧都。

当然qt给定了一个更简单的用法,就是QMutexLocker,就是在函数最开始明明一个局部变量QMutexLocker am(&mutex),这个am会在当前区块被销毁的时候自动释放mutex,就不用自己去慢慢搞了,很麻烦

3.一些旧的类型转换

当然了,你在.h文件里就要把所有的int,bool类型都给初始化了最好,给它个值,或者怎么样,不然可能会出现一些意想不到的问题,比如取到随机的值,这非常操蛋,从之前的麦克风图标问题就老师出现了,到现在还导致好几次崩溃…还有就是老的规范可能允许int直接当bool类型来用,这点也要注意,编译器不会报错,但是你不应该这么写。

4.最重量级的问题:关于结构体,注意每一个warning

这个是真的重量级,因为我今天写代码的时候发现用户在退出的时候会报错,然后报错的位置是一个从列表中找到某一个特定节点的函数,只考虑到了部分情况,而有一些情况没有考虑到!也就是说有时候可能会返回一个混乱的结构体对象出来,里面的东西有,但全是乱的,你没法使用,就会在实际运用中导致一些随机的bug,这是非常恶心的,因为你也不知道bug是怎么产生的,但它就是发生了,看debug 看dmp文件也看不出,因为这个错误并不常规。

最后戴工看了一眼,发现原来是getCamare函数里有可能没返回,这个地方其实在warning里早就提示过了,所以老话说得好啊,warning不是病,坏起来真要命哦。真不知道为什么编译器会让这种问题代码通过编译。事实上还有其他可能,之后我有时间慢慢排查吧,总之这个崩溃问题暂时没有出现了。

3.hover相关

hover有几种方法实现,我稍微浅谈一下

1.qss实现

也就是在qss上的伪状态,这个是最基础的,这个就不细说了。

优点:

这个方法有点就是简单易操作,直接在qss里写好随写随用,非常方便,而且可靠性有保证,没有什么复杂的操作。

缺点:

不够灵活,使用过程中不好去该styleSheet,一般都是在使用前就写好了,而且不能hover触发一些事件

总结:只适合用于设置一些控件的状态,比如按钮的hover,如果更复杂一点的事情就做不了了

注:以下两个方法都需要setMouseTracking(true) 和 setAttribute(WA_Hover)的加持。

2.enterEvent(QEvent *event)

重写这个enterEvent方法,可以让鼠标移动到 (this) 里面的时候检测到 hover事件,并根据需要执行事件

优点:方便,随写随用,是基类函数,可靠,耐操的不二之选

缺点:这个方法是针对当前cpp文件代表的控件全局的,不能细化到某个指定窗口或者控件,具体情况具体分析。

总结:在某些控件内部使用,或者只能针对整个窗口的enterEvent,如果还需要细化,则此方法不适用。

需要设置this->setMouseTracking(true)和 this->setAttribute(WA_Hover,true);

3.eventFilter(QObject *obj,QEvent *event)

这个更是重量级,基本上对控件的任何事件都可以通过eventFilter来截取,但是这个用起来就麻烦很多

优点:精准,优雅,深入

缺点:臃肿的调用方式,不靠谱的性能,拉跨的可靠性

总结:没办法的时候用,比如一定需要hover到某个特定的窗口或者控件

需要从指定窗口到所有的父窗口全部设置setMouseTracking(true),需要设置this->setAttribute(WA_Hover,true)

需要对指定控件设置 ui.widght->installeventFilter(this)

eventFilter 代码实例如下:

bool Mengban::eventFilter(QObject * obj, QEvent * event)
{
  if (obj == ui.btn_mini) {
    if (event->type() == QEvent::MouseButtonPress) {
      on_btn_mini_clicked();
    }
  }

  if (obj == ui.btn_close) {
    if (event->type() == QEvent::KeyPress) {
      return true;
    }
  }
  return false;
}

总之就是优点臃肿,不是很好用,麻烦,但是很没办法的时候只能用这个。

不设置setAttribute(WA_Hover,true)的话,光 setMouseTracking不一定好使

4.全屏轮子

全屏的问题我想了以下,我之前写了几个轮子,不同需求不同想法,我这里写了篇博客,参考文章如下:

三套无边框窗体的方案:可按比例拖拽窗体大小的无边框窗口和几个常见的无边框实例

文档信息

Search

    Table of Contents