1. 程式人生 > 其它 >Qt自帶的陰影類、跨執行緒問題彙總、hover相關、全屏輪子,一些思考。

Qt自帶的陰影類、跨執行緒問題彙總、hover相關、全屏輪子,一些思考。

一點思考:故事的結局重不重要?

我語文不好,但是我數學不好。

我數學不好,但是我英語不好。

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

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

我化學不好,但是我歷史不好。

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

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

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

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

我美術不好,但是我體育不好。

此生什麼都不好,來世什麼都不好。


故事的結局重不重要?之前看到這個辯題,也看了那場精彩的辯論,不得不說名校出來的辯手確實能在短時間內就組織出一套完整的觀點和話術來動搖對方的論點,但我覺得這道題實在出的不好。

故事的結局重要嗎?誠然,如果一個絕好的故事,卻以一個爛透了的結局結束,若以人生做比,一段無疾而終的戀愛,一段沒有終點的旅程,一場沒有屠龍的終點,一局沒有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內的,總之要保證這個視窗的周圍可見,否則這個陰影可能就會出問題。

另外需要注意的一點是,如果這個陰影只是一個單純的分層,請不要設定這個視窗的透明度

比如這樣,你就需要設定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.全屏輪子

全屏的問題我想了以下,我之前寫了幾個輪子,不同需求不同想法,我這裡寫了篇部落格,參考文章如下:

三套無邊框窗體的方案:可按比例拖拽窗體大小的無邊框視窗和幾個常見的無邊框例項