PYQT5:一些按键没有注册keyPressEvent



我的代码是关于的:我目前正在做一个项目,为我电脑中的所有图像创建一个图像浏览器。我已经创建了一个所有图像的数据库,这个应用程序将使我能够在数据库中搜索、查找、查看和循环图像。

我的问题是:我试图读取左箭头键和右箭头键,并将它们连接到一个函数,该函数将按顺序将显示的图像更改为上一个或下一个图像。但由于某种原因,前两次左箭头按压没有对齐,右箭头按压也没有对齐。此外,没有其他按键注册。我的猜测是,发生这种情况是因为箭头键在屏幕上的小部件中循环。需要我如何解决这个问题的想法。

import sys
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtGui as qtg
from PyQt5 import QtCore as qtc
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
self.main_widget = qtw.QWidget()
self.main_widget.setLayout(qtw.QVBoxLayout())
self.main_widget.layout().setSpacing(0)
self.setCentralWidget(self.main_widget)
self.image_label = qtw.QLabel(alignment=qtc.Qt.AlignCenter)
self.image_label.setPixmap(qtg.QPixmap(r'B:LearningPythonimagesimage.jpg'))
self.viewer()
self.menubar()
self.main_widget.layout().addWidget(self.menu_widget)
self.main_widget.layout().addWidget(self.viewer)
self.main_widget.layout().setContentsMargins(0,0,0,0)
self.setStyleSheet("""* {
background-color: #0d0d0d;
}
.QLabel {
border-style: none;
}
.QMainWindow {
border-style: none;
}
""")
self.show()
def menubar(self):
self.menu_widget = qtw.QWidget()
self.menu_widget.setLayout(qtw.QHBoxLayout())
self.menu_widget.layout().setContentsMargins(0,0,0,0)
self.menu_widget.layout().setSpacing(0)
self.menu_widget.layout().setAlignment(qtc.Qt.AlignLeft)
import_btn = qtw.QPushButton('Import')
browser_btn = qtw.QPushButton('Browser', clicked=self.browser_clicked)
import_btn.setFixedWidth(70)
browser_btn.setFixedWidth(70)
self.menu_widget.layout().addWidget(import_btn)
self.menu_widget.layout().addWidget(browser_btn)
self.menu_widget.setStyleSheet("""
QWidget {
background-color: #1f1f1f;
}
.QPushButton {
background-color: #1f1f1f;
color: #fdf8ff;
height: 50px;
border-style: none;
font-weight: bold;
}
.QPushButton::hover {
background-color: white;
}
""")
def viewer(self):
self.viewer = qtw.QMainWindow()
self.viewer.setCentralWidget(self.image_label)
self.dock = qtw.QDockWidget('browser')
# dock.setTitleBarWidget(qtw.QWidget(dock))
self.dock.setStyleSheet('background-color: #1f1f1f; color: #c8cdc8')
self.browser()
self.dock.setWidget(self.browser_widget)
self.dock.setFeatures(qtw.QDockWidget.DockWidgetClosable | qtw.QDockWidget.DockWidgetFloatable)
self.viewer.addDockWidget(qtc.Qt.LeftDockWidgetArea, self.dock)
def browser_clicked(self):
if self.dock.isVisible():
self.dock.hide()
else:
self.dock.show()
if self.dock.isFloating():
self.dock.setFloating(False)
def browser(self):
self.browser_widget = qtw.QMainWindow()
self.browser_main_widget = qtw.QWidget()
self.browser_widget.setCentralWidget(self.browser_main_widget)
self.browser_main_widget.setLayout(qtw.QVBoxLayout())
self.search_box = qtw.QWidget()
self.search_box.setFixedHeight(int(0.15*self.height()))
self.search_box.setLayout(qtw.QFormLayout())
self.browser_main_widget.layout().addWidget(self.search_box)
search_edit = qtw.QLineEdit()
search_edit.setPlaceholderText('Enter search term(s)...')
search_bar = qtw.QHBoxLayout()
filter_options = ['tags', 'name', 'custom...']
filter_option_combobox = qtw.QComboBox()
filter_option_combobox.addItems(filter_options)
filter_option_combobox.setCurrentIndex(0)
filter_option_combobox.currentTextChanged.connect(self.custom_filters)
search_btn = qtw.QPushButton('Search')
search_bar.addWidget(filter_option_combobox)
search_bar.addWidget(search_btn)
self.search_box.layout().addRow(search_edit)
self.search_box.layout().addRow(search_bar)
browser_groupbox = qtw.QGroupBox('Browse')
self.browser_main_widget.layout().addWidget(browser_groupbox)
self.browser_widget.setStyleSheet(""".QLineEdit {
background-color: #4d4d4d;
color: #bbbcbb;
border-style: none;
height: 22px;
}
.QPushButton {
background-color: #ed2553;
color: #fdf8ff;
}
.QComboBox {
background-color: white;
color: black;
height: 20px;
}
""")
def custom_filters(self, value):
if value == 'custom...':
pass
def keyPressEvent(self, event):
if event.key() == qtc.Qt.Key_Left:
print(True)
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = MainWindow()
sys.exit(app.exec_())

更改带有实际图像链接的self.image_label.setPixmap(qtg.QPixmap(r'B:LearningPythonimagesimage.jpg'))行(第14行(,以查看使用实际图像的代码

主要问题是添加了可以获得焦点的小部件,而;观看者";没有焦点,如果不是通过编程方式,它也不能通过键盘/鼠标接受焦点。

结果是,当第一次显示窗口时,Qt将尝试将焦点设置在可以接受中央小部件中的一个小部件上,但由于没有,任何键盘事件都将被忽略。每当您尝试使用箭头键时,Qt将使用";键盘导航";模式,并将找到第一个可以接受焦点的小部件("搜索"按钮,如果向左(,使事件被接受,从而不会传播到主窗口;再往前走,如果你再次向左走;标签";组合将变得集中,再次被接受,而不是传播。

一个临时的解决方法是确保按钮和行编辑只能通过点击获得焦点(但按钮可能根本不应该获得焦点(:

def browser(self):
# ...
search_edit.setFocusPolicy(qtc.Qt.ClickFocus)
filter_option_combobox.setFocusPolicy(qtc.Qt.ClickFocus)
search_btn.setFocusPolicy(qtc.Qt.ClickFocus)

然后,在__init__结束时,您应该将焦点设置在查看器上,可能是在设置了StrongFocus策略之后,如果焦点在另一个小部件上(如行编辑,它显然会接受所有箭头键事件(,该策略将确保它在被点击后获得键盘焦点。

self.viewer.setFocusPolicy(qtc.Qt.StrongFocus)
self.viewer.setFocus()

不幸的是,这不是一个完整的解决方案,因为您的实现还有其他问题。

首先,QMainWindow不应该被用作子窗口小部件(尤其是对于dock(:它是一种非常专业的QWidget类型,有自己的私有布局和事件管理,这可能会导致意外行为
使用简单的QWidget,而不是将QMainWindow添加到dock并作为主查看器。

然后;全局";像这样的键盘事件应该小心管理,因为它们可能会破坏标准使用,或者可能是"错误的";"吃";通过子窗口小部件(意味着这些窗口小部件接受事件,而不将其传播给其父窗口小部件(。这对于像QMainWindow这样的小部件来说是最重要的,它有非常特殊的实现,因为它还可以包括可能需要键盘交互的菜单和工具栏。

一个可能的解决方案是使用QAction,为其设置适当的快捷方式,然后将操作添加到主窗口(这是强制性的,否则永远不会触发(
这种方法的好处是,如果当前关注的小部件实际处理箭头键,它将在不传播的情况下使用它们(这对于行编辑中的键盘导航很重要(,否则快捷方式将触发链接的QAction。

class MainWindow(qtw.QMainWindow):
def __init__(self):
# ...
self.goLeftAction = qtw.QAction('Go left', self)
self.goLeftAction.setShortcut('left')
self.goLeftAction.triggered.connect(self.goLeft)
self.addAction(self.goLeftAction)
self.goRightAction = qtw.QAction('Go right', self)
self.goRightAction.setShortcut('right')
self.goRightAction.triggered.connect(self.goRight)
self.addAction(self.goRightAction)
def goLeft(self):
print('going left')
def goRight(self):
print('going right')

PS:小心在可能有子窗口的窗口小部件上设置的通用样式表(就像你在self.dock中所做的那样(:它们通常会对滚动区域等复杂窗口小部件产生意想不到的结果(包括弹出的QComboBox(。在这些情况下,最好使用适当的选择器类型,可能带有适当的伪状态

最新更新