1. 程式人生 > 其它 >關於在UI介面(QT,PyQT)中去除標題欄,實現自定義最大化,最小化,關閉等功能按鈕

關於在UI介面(QT,PyQT)中去除標題欄,實現自定義最大化,最小化,關閉等功能按鈕

為什麼要自己設計實現標題欄

  • 無論是使用qtdesigner,還是直接在程式中建立一個Qwidget,qt程式生成的介面都會生成一個預設的標題欄。

  • 該標題欄實質上應當是一個邊框,只不過這個邊框上可以顯示ico,標題,可以進行最大化最小化等操作。

  • 標題欄的顏色隨計算機系統的主題變化,且形式固定,如果為介面設定統一的背景和風格,這個標題欄就會非常的突兀,醜陋。因此,如果想要獲得一個和諧的統一的UI介面,我們最好把系統生成的預設標題欄去掉,自己重現預設標題欄附帶的功能。

  • --預設標題欄,在統一背景下顯得很突兀

  • --自定義標題欄,可以自己設計按鍵的大小,圖示,位置,能夠和背景更加統一

想要用自己的就要先去掉別人的

  • --QT程式設計中使用以下語句可以去除系統自動生成的預設邊框。
MainWindow::setWindowFlags(Qt::FramelessWindowHint);//隱藏邊框 
  • 通過修改setWindowFlags的輸入,我們還可以將邊框修改成特殊的樣式,比如只帶一個關閉按鈕。

  • --python中該語句的寫法為:

self.setWindowFlags(Qt.FramelessWindowHint) # 隱藏邊框 

去掉標題欄後我們會失去什麼

  • 前文說過,標題欄的本質是一個邊框,或者說一個group,這個邊框作為限制,UI內容巢狀在邊框裡,而邊框則“懸浮”在桌面上。
  1. 因此,去除邊框後,首當其衝,UI介面會因為失去邊框丟失調整大小的能力,表現出來的就是滑鼠無法選中介面的邊緣,達到拖動邊緣改變大小的目的。

  2. 同時,因為改變介面在桌面上的位置原本由邊框實現,去除邊框後,UI與桌面不存在明確的佈局關係,介面內容將無法移動。

  3. 原本程式的最大化(還原),最小化,關閉等功能由標題欄的按鈕實現,去除標題欄後,該類操作介面的方式就會消失,不過我們仍可以通過底部狀態列右鍵操作介面。

  4. 總結而言,去除標題欄後,我們將無法通過按鈕對介面進行最大化(還原),最小化,關閉等操作,無法拖動介面,也無法改變介面的大小,而這些也將是我們後續亟待實現的功能。

如何在程式中實現最大化(還原),最小化,關閉等操作

  • QT是一個比較傻瓜化的介面繪製方式,針對介面中常備的繪製,關閉等操作,QT架構中有一系列的事件可供呼叫和修改來幫助編寫者較簡單的實現這些功能。因此在去除標題欄後,我們僅需要在介面中新增上想要的按鈕,命名後放好想要的位置。通過設定風格等方式修改好按鈕的樣式和標籤,我們就能通過呼叫上文中描述的事件來替代預設標題欄。

1. 放置按鈕,調整位置,並修改成自己想要的風格。

  • --這裡給出一段我常用的按鈕樣式表,該樣式表分別定義了按鈕的背景色,滑鼠懸浮效果和按下的效果。

QPushButton{background-color:rgba(0,0,0,0);} 

QPushButton:hover{background-color:rgba(255,255,255,0.5);} 

QPushButton:pressed{background-color: rgba(100,100,100,1);}; 

2. 準備好符合自己介面風格的各按鈕標誌,並提前新增到QT的素材檔案(.qrc)裡。

  • --標誌應符合介面風格,且應和背景顏色不同,因為我做的暗色介面較多所以這裡是純白色的,沒有特殊設計的話這些按鈕的背景應當是透明的,我們可以在ps裡面很簡單的自己繪製一個想要的標誌,然後儲存為png格式後,再在網上找一個轉換的網站轉換為ico格式

3. 關閉按鈕實現。

  • 如果不涉及對關閉介面事件的修改,我們僅需在想要的按鈕clicked槽函式下呼叫QT預設的close事件即可。

  • --QT中其呼叫格式為:

void MainWindow::on_pushButton_close_clicked() 
{ 
    MainWindow::close();//關閉事件 
} 
  • --python中,其呼叫格式更接近訊號與槽的格式:
self.pushButton_close.clicked.connect(self.close) 
  • 如果需要修改關閉事件,比如在python多程序程式設計中需要保證主程序關閉帶動子程序一起關閉,則需要對closeevent中內容進行修改。

  • --其在QT中呼叫格式如下:

void MainWindow::closeEvent(QCloseEvent *event) 
{ 

} 
  • --在python中呼叫如下:
# 關閉主視窗時清理資源 
def closeEvent(self, event): 
    data = "---Visual shield tail clearance measurement system off." 
    ms = Measurement_data_sava(cctv_par.address, data, forma=4, save_lev=1, log_lev=0)       
    kill_name(uwb_par.name_pid) 

4. 最大化(還原)按鈕實現,最小化按鈕實現。

  • --最大化(還原)按鈕QT中實現方式如下:
void MainWindow::on_pushButton_maximize_clicked() 
{ 
    if (MainWindow::isMaximized()) 
    { 
        MainWindow::showNormal();//還原事件 
        ui->pushButton_maximize->setIcon(QIcon(QPixmap(":/new/new/max.png"))); 
    } 
    else 
    { 
        MainWindow::showMaximized();//最大化事件 
        ui->pushButton_maximize->setIcon(QIcon(QPixmap(":/new/new/back.png"))); 
    } 
} 
  • 利用MainWindow::isMaximized()可以判斷UI介面當前的狀態,以分別實現最大化和還原的功能。

  • 功能切換時注意更換按鈕上顯示的標誌,以顯示其當前真正的功能。

  • --python中最大化(還原)按鈕實現方式如下:

# 呼叫 
self.pushButton_max .clicked.connect(self.maxornormale) 

# 最大化按鈕功能
def maxornormale(self):
    if self.isMaximized():
        self.flgs_max_normal=0
        self.showNormal()
        icon7 = QtGui.QIcon()
        icon7.addPixmap(QtGui.QPixmap(":/newPrefix/resource/icon/max.png"), QtGui.QIcon.Normal,
                        QtGui.QIcon.Off)
        self.pushButton_max.setIcon(icon7)
    else:
        self.flgs_max_normal = 1
        self.showMaximized()
        icon6 = QtGui.QIcon()
        icon6.addPixmap(QtGui.QPixmap(":/newPrefix/resource/icon/back.png"), QtGui.QIcon.Normal,
                        QtGui.QIcon.Off)
        self.pushButton_max.setIcon(icon6)
  • --最小化按鈕QT中實現方式如下:
void MainWindow::on_pushButton_minimize_clicked() 
{ 
    MainWindow::showMinimized(); 
} 
  • --最小化按鈕python中實現方式如下:
self.pushButton_min .clicked.connect(self.showMinimized) 

實現介面移動

  • 聯想一下,正常情況下介面移動的操作過程是什麼?滑鼠左鍵長按標題欄中的非按鈕位置,然後拖動滑鼠,介面從起始位置移動到滑鼠停留的位置。在此過程中,起到定位作用的引數分別有,介面當前的位置,滑鼠游標的起始位置,滑鼠游標終止位置,起到觸發作用則是滑鼠左鍵的長按動作。

  • 用QT程式設計的思路解析該過程,可以表述為:滑鼠左鍵長按作為訊號,該訊號觸發的槽函式為計算操作過程中滑鼠位置的變化,再將介面按滑鼠位置的變化移動,達成滑鼠拖動介面的效果。

  • 因此,根據上述分析,滑鼠拖動介面移動的實現至少需要兩個部分:

    1. 識別滑鼠的長按動作及落點,長按動作用於觸發移動操作,落點則用於判斷當前位置應不應該移動介面。
    
    2. 根據記錄的滑鼠位置,計算出滑鼠在桌面座標系中的變化,再將介面按照變化調整位置。
    
  • 這些動作都可以通過滑鼠事件解決。

1. 通過滑鼠點選事件,識別滑鼠左鍵按下操作,並記錄當前位置:

  • --QT中該操作的實現方式為:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        whereismouse=event->pos();
    }

}
  • --python中該操作的實現方式為:
# 滑鼠事件,按下按鍵
def mousePressEvent(self, e):
    if e.buttons() == QtCore.Qt.LeftButton:
        try:
            self.mos = e.pos()
        except:
            pass

2. 通過滑鼠移動事件,計算滑鼠游標的座標變化,並藉助move事件使介面進行相同的移動。

  • --QT中該操作的實現方式為:
void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() == Qt::LeftButton)
    {
        if(MainWindow::isMaximized() || MainWindow::isMinimized())
        {
            return;
        }
        else
        {
            if (ui->groupBox_top->underMouse())
            {
                if(ui->groupBox_2->underMouse())
                {

                }
                else
                {
                    MainWindow::move(MainWindow::mapToGlobal(event->pos()-whereismouse));
                }
            }
        }
    }
    event->accept();
}

  • --python中該操作的實現方式為:
# 滑鼠移動事件
def mouseMoveEvent(self, event):
    if self.pushButton_tip.underMouse():
        pass
    elif self.pushButton_4.underMouse():
        pass
    elif self.pushButton_5.underMouse():
        pass
    else:
        try:
            if event.buttons() == Qt.LeftButton and self.mos:
                self.move(self.mapToGlobal(event.pos() - self.mos))
            event.accept()
        except:
            pass
  • underMouse()語句可以獲取滑鼠當前是否懸浮在相應控制元件上,通過該語句可以控制介面拖動的生效範圍,使其不在按鈕之類需要滑鼠操作的地方誤觸發。