PyQt5循环导航栏烦恼

问题描述 投票:0回答:2

我正在编写一个脚本,该脚本在底部有一个滚动导航菜单,由旋转编码器导航。一次应该只显示 3 个图标,中心图标始终较大,并且当用户到达列表末尾时,它应该顺利地从开头继续返回。这可以正常工作,直到我到达列表的末尾,但随后它会打破列表中最后一个和第一个成员的模式。

IE,应该是这样的:

0 [1] 2
1 [2] 3
2 [3] 4
3 [4] 5
4 [5] 0
5 [0] 1

但我得到的实际模式是:

0 [1] 2
1 [2] 3
2 [3] 4
3 [4] 5
0 4 [5]
[0] 1 5

这是完整代码

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QGridLayout
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt, QTimer
import board
import busio
from adafruit_seesaw.seesaw import Seesaw
from adafruit_seesaw.rotaryio import IncrementalEncoder

# Rotary Encoder setup
i2c = busio.I2C(board.SCL, board.SDA)
ss = Seesaw(i2c, addr=0x49)
encoder = IncrementalEncoder(ss)
last_position = encoder.position

class RotaryInterface(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowState(Qt.WindowFullScreen)
        self.setStyleSheet("background-color: blue;")
        self.font_small = QFont('Symbola', 30)
        self.font_large = QFont('Symbola', 50)

        self.symbols_with_effects = [
            ("\U0001F31F", "Glowing Star"),
            ("\U0001F3A8", "Artist Palette"),
            ("\U0001F680", "Rocket"),
            ("\U0001F340", "Four Leaf Clover"),
            ("\U0001F308", "Rainbow"),
            ("\U0001F319", "Crescent Moon")
        ]

        self.labels = [QLabel(sym[0], self) for sym in self.symbols_with_effects]
        self.symbol_layout = QGridLayout()
        self.symbol_layout.setSpacing(0)
        self.setLayout(self.symbol_layout)
        for i, label in enumerate(self.labels):
            label.setFont(self.font_small)
            label.setAlignment(Qt.AlignBottom | Qt.AlignHCenter)
            self.symbol_layout.addWidget(label, 0, i)

        self.selected = 1
        self.visible_icons = self.calculateVisibleIcons()
        self.updateDisplay()

        self.timer = QTimer(self)
        self.timer.timeout.connect(self.checkEncoder)
        self.timer.start(100)

        self.close_button = QPushButton(chr(0x274E), self)
        self.close_button.setFont(QFont('Symbola', 50))
        self.close_button.setStyleSheet("QPushButton { background-color: rgba(0, 0, 0, 0); color: red; border: 0px; }"
                                        "QPushButton:hover, QPushButton:pressed, QPushButton:focus {"
                                        "background-color: rgba(0, 0, 0, 0); color: red; border: 0px;}")
        self.close_button.setFlat(True)
        self.close_button.setGeometry(700, 0, 100, 100)
        self.close_button.clicked.connect(self.close)

    def calculateVisibleIcons(self):
        num_icons = len(self.symbols_with_effects)
    
        # When selected is the first icon
        if self.selected == 0:
            return [num_icons - 1, self.selected, self.selected + 1]
    
        # When selected is the last icon
        elif self.selected == num_icons - 1:
            return [self.selected - 1, self.selected, 0]

        # For all other cases
        else:
            return [self.selected - 1, self.selected, self.selected + 1]

    def updateDisplay(self):
        # Hide all labels initially
        for label in self.labels:
            label.hide()

        # Show and set font for visible icons
        for index in self.visible_icons:
            label = self.labels[index]
            label.show()
            if index == self.selected:
                label.setFont(self.font_large)
            else:
                label.setFont(self.font_small)

    def checkEncoder(self):
        global last_position
        position = encoder.position
        if position != last_position:
            delta = position - last_position
            self.selected = (self.selected + delta) % len(self.symbols_with_effects)
            self.visible_icons = self.calculateVisibleIcons()
            self.updateDisplay()
            last_position = position

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = RotaryInterface()
    ex.show()
    sys.exit(app.exec_())

我尝试更新

calculateVisibleIcons
方法来显式处理结束和开始,但这并不能解决问题


    def calculateVisibleIcons(self):
        num_icons = len(self.symbols_with_effects)
        
        # When selected is the first icon
        if self.selected == 0:
            return [num_icons - 1, self.selected, self.selected + 1]
        
        # When selected is the last icon
        elif self.selected == num_icons - 1:
            return [self.selected - 1, self.selected, 0]

        # For all other cases
        else:
            return [self.selected - 1, self.selected, self.selected + 1]

我似乎在这里犯了一个简单的逻辑错误,但我似乎无法弄清楚。谢谢。

python pyqt5
2个回答
0
投票

啊!刚刚想通了。解决方法是在环绕期间显式管理 qgridlayout 中 qlabel 小部件的位置,确保它们根据正确的顺序重新定位并刷新。

    def updateDisplay(self):
    # Hide all labels initially and remove them from the layout
    for label in self.labels:
        label.hide()
        self.symbol_layout.removeWidget(label)

    # Reposition and show the visible icons in the layout
    for i, index in enumerate(self.visible_icons):
        label = self.labels[index]
        label.show()
        if index == self.selected:
            label.setFont(self.font_large)
        else:
            label.setFont(self.font_small)
        # Update the position in the grid layout
        self.symbol_layout.addWidget(label, 0, i)

0
投票

您只是更改小部件的可见性,而不是它们的顺序。

将标签添加到布局时,它们按以下顺序排列:

[0] [1] [2] [3] [4] [5]

如果您随后设置可见标签 4、5 和 0,则小部件仍位于其位置:

[0] --- --- --- [4] [5]

隐藏或显示小部件的顺序完全无关。

为了“移动”标签的位置,您应该将其删除并再次添加到布局中。

请注意,在这些情况下,您应该始终使用专用布局,该布局不得与其他小部件共享。

QGridLayout 也未指示用于此类目的,并且水平框布局更合适,因为项目索引排序会在删除或插入时自动调整。

class RotaryInterface(QWidget):
    ...
    def initUI(self):
        ...
        self.main_layout = QVBoxLayout(self)
        self.symbol_layout = QHBoxLayout()
        self.main_layout.addLayout(self.symbol_layout)
        ...

    def updateDisplay(self):
        # Only hide not visible labels and remove them from the layout
        for i, label in enumerate(self.labels):
            if not i in self.visible_icons:
                label.hide()
                self.symbol_layout.removeWidget(label)

        lastIndex = -1
        for index in self.visible_icons:
            label = self.labels[index]
            if index == self.selected:
                label.setFont(self.font_large)
            else:
                label.setFont(self.font_small)
            if index < lastIndex:
                self.symbol_layout.removeWidget(label)
            self.symbol_layout.addWidget(label)
            label.show()
            lastIndex = index

这个概念是,如果“新”小部件的索引低于前一个,则应将其删除并添加到布局的“末尾”。

© www.soinside.com 2019 - 2024. All rights reserved.