根据标签大小调整窗口大小不考虑pyQT5中的标题栏
我正在编写一个简单的图像查看器,并希望窗口根据我打开的图像调整大小。
我使用的窗口是 QMainWindow 并且有一个工具栏。我唯一的小部件是 QLabel,它被设置为中央小部件。当我打开图像时,我使用 self.resize(self.label.sizeHint()) ,但窗口大小没有考虑标题栏和工具栏的大小,例如如果我打开 400x400 的图像,窗口的宽度将是正确的,但有点太短了。
计算正确窗口大小以便在每个平台上正确调整大小的正确方法是什么? (Windows、macOS、Linux)
编辑:最少的代码是:
import PyQt5.QtWidgets as w
import PyQt5.QtGui as g
import PyQt5.QtCore as c
import sys
class ImageViewerWindow(w.QMainWindow):
def __init__(self):
super().__init__()
self.loadedImagePaths = []
self.imageIndex = 0
self.scrollArea = w.QScrollArea()
self.label = w.QLabel()
self.setCentralWidget(self.scrollArea)
self.scrollArea.setWidgetResizable(True)
self.label.setAlignment(c.Qt.AlignCenter)
self.label.setMinimumSize(1,1)
# Actions
self.openAction = w.QAction("Open...", self)
self.openAction.setShortcut(g.QKeySequence.Open)
self.openAction.triggered.connect(self.openMenuDialog)
# Toolbar elements
toolbar = w.QToolBar("Top toolbar")
toolbar.setMovable(False)
toolbar.setContextMenuPolicy(c.Qt.PreventContextMenu)
self.addToolBar(toolbar)
# Status bar elements
self.setStatusBar(w.QStatusBar(self))
# Add actions to toolbar and menu
toolbar.addAction(self.openAction)
def showImageAtIndex(self, index):
image = g.QPixmap(self.loadedImagePaths[index])
self.label.setPixmap(image)
self.scrollArea.setWidget(self.label)
self.imageIndex = index
self.angle = 0
self.label.adjustSize()
self.resize(self.label.sizeHint())
def openMenuDialog(self, firstStart = False):
self.loadedImagePaths, _ = w.QFileDialog.getOpenFileNames(parent=self, caption="Select one or more JPEG files to open:", filter="JPEG Image(*.jpg *.jpeg)")
if self.loadedImagePaths:
if firstStart:
self.show()
self.imageIndex = 0
self.showImageAtIndex(self.imageIndex)
elif firstStart:
sys.exit()
a = w.QApplication([])
ivw = ImageViewerWindow()
ivw.openMenuDialog(firstStart = True)
a.exec()
如果您尝试打开图像然后调整窗口大小,您会注意到一些图像被标题栏和状态栏覆盖。
I'm coding a simple image viewer and would like for the window to resize based on the image that I open.
The window I'm using is a QMainWindow and has a toolbar. The only widget I have is a QLabel which is set as the central widget. When I open the image I use self.resize(self.label.sizeHint())
, but the window size doesn't take into account the size of the title bar and the toolbar, so for example if I open a 400x400 image the window will be of the correct width, but a little bit too short.
What would be the correct way to calculate the correct window size so that it resizes correctly on every platform? (Windows, macOS, Linux)
EDIT: the minimal code is:
import PyQt5.QtWidgets as w
import PyQt5.QtGui as g
import PyQt5.QtCore as c
import sys
class ImageViewerWindow(w.QMainWindow):
def __init__(self):
super().__init__()
self.loadedImagePaths = []
self.imageIndex = 0
self.scrollArea = w.QScrollArea()
self.label = w.QLabel()
self.setCentralWidget(self.scrollArea)
self.scrollArea.setWidgetResizable(True)
self.label.setAlignment(c.Qt.AlignCenter)
self.label.setMinimumSize(1,1)
# Actions
self.openAction = w.QAction("Open...", self)
self.openAction.setShortcut(g.QKeySequence.Open)
self.openAction.triggered.connect(self.openMenuDialog)
# Toolbar elements
toolbar = w.QToolBar("Top toolbar")
toolbar.setMovable(False)
toolbar.setContextMenuPolicy(c.Qt.PreventContextMenu)
self.addToolBar(toolbar)
# Status bar elements
self.setStatusBar(w.QStatusBar(self))
# Add actions to toolbar and menu
toolbar.addAction(self.openAction)
def showImageAtIndex(self, index):
image = g.QPixmap(self.loadedImagePaths[index])
self.label.setPixmap(image)
self.scrollArea.setWidget(self.label)
self.imageIndex = index
self.angle = 0
self.label.adjustSize()
self.resize(self.label.sizeHint())
def openMenuDialog(self, firstStart = False):
self.loadedImagePaths, _ = w.QFileDialog.getOpenFileNames(parent=self, caption="Select one or more JPEG files to open:", filter="JPEG Image(*.jpg *.jpeg)")
if self.loadedImagePaths:
if firstStart:
self.show()
self.imageIndex = 0
self.showImageAtIndex(self.imageIndex)
elif firstStart:
sys.exit()
a = w.QApplication([])
ivw = ImageViewerWindow()
ivw.openMenuDialog(firstStart = True)
a.exec()
If you try and open an image and then resize the window you will notice that some of the image is covered by the title bar and the status bar.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
主要问题是使用
setWidgetResizing()
:因此您必须删除该行,或在标签上使用
setFixedSize()
使用图像尺寸。然后,在标签上调用
adjustSize()
是不够的,因为您实际上需要针对顶级窗口调用adjustSize()
:这是因为调用resize ()
与图像大小不会考虑窗口中的所有其他小部件(在您的情况下,工具栏和状态栏)。不幸的是,这还不够,因为 QScrollArea 缓存了小部件的大小提示,并且使用相同的小部件再次调用
setWidget()
是没有用的。最简单的解决方案是使用 QScrollArea 的子类并重新实现
sizeHint()
。最后,对齐方式仅对标签内容有影响,但是当将小部件添加到容器时,必须为小部件设置对齐。
请注意,只有在尺寸不超过屏幕尺寸的 2/3 之前,才会考虑顶级窗口的尺寸提示。这意味着,如果图像强制窗口尺寸稍大,则至少会显示一个滚动条,即使这并不是绝对必要的。
对此没有明显或通用的解决方案,您需要找到自己的方法。例如,您可以在调整大小后检查滚动条是否可见,并最终比较图像的大小和滚动区域视口的大小,然后如果以下之一图像尺寸仅小了相对滚动条的大小,强制根据该滚动条大小调整顶层窗口的大小。
The main problem is that using
setWidgetResizable()
:So you have to remove that line, or use
setFixedSize()
on the label using the image size.Then, calling
adjustSize()
on the label is not enough, as you actually need to calladjustSize()
against the top level window: this is because callingresize()
with the image size won't consider all other widgets in the window (in your case, the toolbar and status bar).Unfortunately, that won't be enough, as QScrollArea caches the size hint of the widget, and calling again
setWidget()
with the same widget is useless.The easiest solution is to use a subclass of QScrollArea and reimplement the
sizeHint()
.Finally, the alignment only has effect on the label contents, but when the widget is added to a container the alignment has to be set for the widget.
Note that the size hint of a top level window will only be respected until the size doesn't exceed 2/3 of the screen size. This means that if the image will force the window to a slightly bigger size, at least one scroll bar will be shown, even if it's not strictly necessary.
There is no obvious nor universal solution for that, and you need to find your own way. For instance, you can check if the scroll bars are visible after adjusting the size and eventually compare the size of the image and that of the scroll area's viewport, then if one of the image dimensions is just smaller by the size of the opposite scroll bar, force a resizing of the top level window by that scroll bar size.