天天看點

Pyqt5 自制的滾動條

##唠嗑唠嗑

Pyqt5的滾動條很不美觀,特别是pyinstaller後的樣子更醜。我研究了兩天翻了無數的資料,都是推薦我用QSS寫的。但是,現在我用算法就已經能夠實作了。而且不管你将滾動按鈕變成任何的樣子都可以用。前提是你已經将我的代碼吃透了。

代碼

下面我會給出代碼,全部已經标上注釋了,理不了解要靠個人:

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
 
class QLabel_scro(QLabel):
    move_scroll = pyqtSignal() # 定義一個信号
    widget_bottom = 0 # 這裡是獲得 scro(滾動條) 高度的值
    last_move = 0 # 這個是用來存放上一次移動了滾動按鈕的頂點值的值
    def __init__(self,*args):
        super(QLabel_scro, self).__init__(*args)
 
    # 滑鼠點選
    def mousePressEvent(self, e):
        if e.button() == Qt.LeftButton: # 隻接受左鍵點選
            self._drag = True # 這個是用來判斷是否被點選
            self._DragPosition = e.globalPos() - self.pos() # 這個是獲得滾動按鈕的頂點值距離中心點的值
            e.accept()
            self.setCursor(QCursor(Qt.PointingHandCursor)) # 改變滑鼠指針
 
    # 滑鼠釋放
    def mouseReleaseEvent(self, e):
        if e.button() == Qt.LeftButton:
            self._drag = False # 将是否點選變成 false
            self.setCursor(QCursor(Qt.ArrowCursor)) # 改變滑鼠指針
 
    def mouseMoveEvent(self, e):
        if self.last_move == 0: # 判斷是否為0 (第一次啟動要變成這個,不然會報錯,因為函數在類這個全局中建立了)
            self.last_move = self.pos().y() # 将值變成按鈕頂點的值
        self.demove = self.pos().y() - self.last_move # 這裡是移動後的值減去上一次移動的值
        self.move_scroll.emit() # 傳到信号
        self.last_move = self.pos().y() # 獲得目前的值
        yx = (e.globalPos() - self._DragPosition).y() # 這裡是将目前按鈕的中心點減去滾動按鈕的頂點值距離中心點的值就可以獲得目前按鈕的頂點值
        _yx = yx + self.height() # 這裡是将頂點的值加上自身的高度就等于底端的值了
        if _yx <= self.widget_bottom and yx >= 0: # 給按鈕的移動限制範圍 (就是底端的值不能超過滾動條的高度,頂點的值不能小于0)
            self.move(0, yx) # 符合就移動
            e.accept()
 
class QS(QScrollArea):
 
    def __init__(self,*args):
        super(QS, self).__init__(*args)
    def wheelEvent(self, e):
        pass # 這裡是取消了原有的滾動條滾動時的操作 以免出現滾動了而我們自己的滾動條按鈕沒有變化
 
class Ui_Form(QWidget):
    def __init__(self,parent=None):
        super(Ui_Form, self).__init__(parent=None)
        self.setObjectName("self")
        self.resize(1000, 1000)
        self.scroll_area = QS(self) # 建立滾動範圍
        self.scroll_area.setGeometry(0, 0, 400, 400)
        self.scroll_area.setWidgetResizable(False) # 将自動調整大小關閉
        self.scroll_bar = self.scroll_area.verticalScrollBar() # 重要的一步,擷取滾動範圍的滾動條!!!
 
        self.scroll_contents = QWidget() # 建立一個可以被滾動的視口
        self.scroll_contents.setGeometry(0, 0, 400, 800)
        self.scroll_contents.setMinimumSize(380, 1000) # 可要可不要
 
        self.label_1 = QLabel(self.scroll_contents)
        self.label_1.move(50, 100)
        self.label_1.setText("HelloRyan")
 
        self.label_2 = QLabel(self.scroll_contents)
        self.label_2.move(50, 200)
        self.label_2.setText("你好")
 
        self.label_3 = QLabel(self.scroll_contents)
        self.label_3.move(50, 300)
        self.label_3.setText("-----------")
 
        self.label_4 = QLabel(self.scroll_contents)
        self.label_4.move(50, 400)
        self.label_4.setText("542543255235432543252")
 
        self.label_5 = QLabel(self.scroll_contents)
        self.label_5.move(50, 500)
        self.label_5.setText("5432543262542")
 
        self.label_6 = QLabel(self.scroll_contents)
        self.label_6.move(50, 600)
        self.label_6.setText("4325432532")
 
        self.scroll_area.setWidget(self.scroll_contents)
        self.scroll_area.installEventFilter(self)
 
        self.retranslateUi()
        QMetaObject.connectSlotsByName(self)
        # ----------------------------------------------------
 
        self.scro = QWidget(self) # 建立滾動條
        self.scro.setGeometry(QRect(500, 20, 10, self.scroll_area.height()))
        self.scro.setObjectName("widget")
        self.scro.setStyleSheet("QWidget{background-color:#fff;}")
        self.scro_w = QLabel_scro(self.scro) # 建立滾動按鈕
        self.scro_w.widget_bottom = self.scro.height() # 将滾動條的高度傳到到滾動按鈕 這一步是為了适應改變了滾動條高度的問題和對于滾動按鈕的限制
        self.scro_w.setGeometry(QRect(0, 0, 10, 81))
        self.scro_w.setStyleSheet("QLabel{background-color:#d7d7d7;border-radius:5px;}\n"
            "QLabel:hover{background-color:#b3b3b3;}")
        self.scro_w.setObjectName("label")
 
        self.scro_w.move_scroll.connect(self.Move) # 連接配接事件
        self.scroll_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # 将滾動範圍的滾動條關閉
    def retranslateUi(self):
        _translate = QCoreApplication.translate
        self.setWindowTitle(_translate("self", "self"))
 
    def wheelEvent(self,e):
        y = self.scro_w.pos().y() # 獲得滾動按鈕的頂點位置
        _y = y + self.scro_w.height() # 獲得滾動按鈕的底部位置
        if e.angleDelta().y() > 0: # 這個是獲得滑鼠滾輪的值 它的值隻有 120 和 -120 由此來判斷是向上還是向下移動
            if _y <= self.scro_w.widget_bottom and y >= 0: # 限制範圍
                if (_y + 10) >= self.scro_w.widget_bottom: # 因為以10的值來增加肯定會超出滾動條的範圍的,是以這個是預先判斷下一次向下滾動是否會超過滾動條的高度
                    self.scro_w.move(0,self.scro_w.widget_bottom - self.scro_w.height()) # 如果超過就取當按鈕到底部時按鈕的頂部位置
                    self.scroll_bar.setValue(623) # 這裡面的值是滾動範圍的滾動條的最大值,如果不知道最大值是多少請自行使用下面被注釋的# print(self.scroll_bar.value())來檢視
                else:
                    self.scro_w.move(0,y+10) # 如果不是就将滾動按鈕移動位置
                    self.scroll_bar.setValue(self.scroll_bar.value() + 20) # 同時移動滾動範圍的滾動條
        else:
            if _y <= self.scro_w.widget_bottom and y >= 0: # 限制範圍
                if (y - 10) <= 0: # 同樣的預先判斷下一次向上滾動是否會超過 0
                    self.scro_w.move(0,0) # 這裡就很簡單了,就直接給 0 即可
                    self.scroll_bar.setValue(0) # 同樣的給上滾動範圍的滾動條的值
                else:
                    self.scro_w.move(0,y-10) # 如果不是就将滾動按鈕移動位置
                    self.scroll_bar.setValue(self.scroll_bar.value() - 20) # 同時移動滾動範圍的滾動條的值
 
    def Move(self):
        self.scroll_bar.setValue(self.scroll_bar.value() + (self.scro_w.demove * 2)) # 給滾動條的值移動滾動條使可視區域改變 (這裡的乘2要根據你自己來判斷是否要或者不要)
        # self.scroll_bar.setValue(self.scroll_bar.value() + self.scro_w.demove ) # 一般是不要的,不知道這裡的算法為什麼有問題
        # print(self.scroll_bar.value())
 
if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = Ui_Form()
    ex.show()
    sys.exit(app.exec_())
           

看不懂的地方可以私信我哦

我的郵箱:[email protected]