Я изо всех сил пытаюсь решить, как заставить все вещи в названии работать вместе в определенной ситуации. Я использую PyQt5 здесь, но не стесняйтесь отвечать обычным C ++ Qt, поскольку я могу довольно легко переводить.
Я пытаюсь создать пользовательский интерфейс со следующим:
-
Основная форма (наследует от QWidget
, может также использовать QMainWindow
)
Основная форма должна содержать QSplitter
, ориентированную вертикально, содержащую QTextEdit
вверху и содержит пользовательский класс (унаследованный от QLabel
) для отображения изображения, занимающего оставшуюся часть пространства.
Значение QTextEdit
вверху по умолчанию должно составлять примерно 3 строки текста высотой, но это должно быть изменяемого размера до любого разумного предела через QSplitter
.
Пользовательский класс должен изменить размер изображения, чтобы быть максимально большим, учитывая доступное пространство при сохранении соотношения сторон.
Конечно, хитрая часть заставляет все корректно изменить размер в зависимости от того, какой у пользователя большой монитор и как перемещается форма. Мне нужно, чтобы это работало на экранах размером около 1000 пикселей в ширину и, возможно, размером более 3000 пикселей в ширину.
Вот что у меня есть:
# QSplitter3.py
import cv2
import numpy as np
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QVBoxLayout, QLabel, QGridLayout, QSizePolicy, \
QFrame, QTabWidget, QTextEdit, QSplitter
from PyQt5.QtGui import QImage, QPixmap, QPainter
from PyQt5.Qt import Qt
from PyQt5.Qt import QPoint
def main():
app = QApplication([])
screenSize = app.primaryScreen().size()
print('screenSize = ' + str(screenSize.width()) + ', ' + str(screenSize.height()))
mainForm = MainForm(screenSize)
mainForm.show()
app.exec()
# end function
class MainForm(QWidget):
def __init__(self, screenSize):
super().__init__()
# set the title and size of the Qt QWidget window
self.setWindowTitle('Qt Window')
self.setGeometry(screenSize.width() * 0.2, screenSize.height() * 0.2,
screenSize.width() * 0.5 , screenSize.height() * 0.7)
# declare a QTextEdit to show user messages at the top, set the font size, height, and read only property
self.txtUserMessages = QTextEdit()
self.setFontSize(self.txtUserMessages, 14)
self.txtUserMessages.setReadOnly(True)
# make the min height of the text box about 2 lines of text high
self.txtUserMessages.setMinimumHeight(self.getTextEditHeightForNLines(self.txtUserMessages, 2))
# populate the user messages text box with some example text
self.txtUserMessages.append('message 1')
self.txtUserMessages.append('message 2')
self.txtUserMessages.append('message 3')
self.txtUserMessages.append('stuff here')
self.txtUserMessages.append('bla bla bla')
self.txtUserMessages.append('asdasdsadds')
# instantiate the custom ImageWidget class below to show the image
self.imageWidget = ImageWidget()
self.imageWidget.setMargin(0)
self.imageWidget.setContentsMargins(0, 0, 0, 0)
self.imageWidget.setScaledContents(True)
self.imageWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.imageWidget.setAlignment(Qt.AlignCenter)
# declare the splitter, then add the user message text box and tab widget
self.splitter = QSplitter(Qt.Vertical)
self.splitter.addWidget(self.txtUserMessages)
self.splitter.addWidget(self.imageWidget)
defaultTextEditHeight = self.getTextEditHeightForNLines(self.txtUserMessages, 3)
print('defaultTextEditHeight = ' + str(defaultTextEditHeight))
# How can I use defaultTextEditHeight height here, but still allow resizing ??
# I really don't like this line, the 1000 is a guess and check that may only work with one screen size !!!
self.splitter.setSizes([defaultTextEditHeight, 1000])
# Should setStretchFactor be used here ?? This does not seem to work
# self.splitter.setStretchFactor(0, 0)
# self.splitter.setStretchFactor(1, 1)
# What about sizeHint() ?? Should that be used here, and if so, how ??
# set the main form's layout to the QGridLayout
self.gridLayout = QGridLayout()
self.gridLayout.addWidget(self.splitter)
self.setLayout(self.gridLayout)
# open the two images in OpenCV format
self.openCvImage = cv2.imread('image.jpg')
if self.openCvImage is None:
print('error opening image')
return
# end if
# convert the OpenCV image to QImage
self.qtImage = openCvImageToQImage(self.openCvImage)
# show the QImage on the ImageWidget
self.imageWidget.setPixmap(QPixmap.fromImage(self.qtImage))
# end function
def setFontSize(self, widget, fontSize):
font = widget.font()
font.setPointSize(fontSize)
widget.setFont(font)
# end function
def getTextEditHeightForNLines(self, textEdit, numLines):
fontMetrics = textEdit.fontMetrics()
rowHeight = fontMetrics.lineSpacing()
rowHeight = rowHeight * 1.21
textEditHeight = int(numLines * rowHeight)
return textEditHeight
# end function
# end class
def openCvImageToQImage(openCvImage):
# get the height, width, and num channels of the OpenCV image, then compute the byte value
height, width, numChannels = openCvImage.shape
byteValue = numChannels * width
# make the QImage from the OpenCV image
qtImage = QImage(openCvImage.data, width, height, byteValue, QImage.Format_RGB888).rgbSwapped()
return qtImage
# end function
class ImageWidget(QLabel):
def __init__(self):
super(QLabel, self).__init__()
# end function
def setPixmap(self, pixmap):
self.pixmap = pixmap
# end function
def paintEvent(self, event):
size = self.size()
painter = QPainter(self)
point = QPoint(0, 0)
scaledPixmap = self.pixmap.scaled(size, Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation)
point.setX((size.width() - scaledPixmap.width()) / 2)
point.setY((size.height() - scaledPixmap.height()) / 2)
painter.drawPixmap(point, scaledPixmap)
# end function
# end class
if __name__ == '__main__':
main()
В настоящее время я ' m тестирование на экране 2560x1440 и с введенными значениями magi c 1000
, оно работает на этом размере экрана, но мне действительно не нравится жестко запрограммированный 1000
. Я подозреваю, что область кода, где я что-то упускаю, является этой частью:
# declare the splitter, then add the user message text box and tab widget
self.splitter = QSplitter(Qt.Vertical)
self.splitter.addWidget(self.txtUserMessages)
self.splitter.addWidget(self.imageWidget)
defaultTextEditHeight = self.getTextEditHeightForNLines(self.txtUserMessages, 3)
print('defaultTextEditHeight = ' + str(defaultTextEditHeight))
# How can I use defaultTextEditHeight height here, but still allow resizing ??
# I really don't like this line, the 1000 is a guess and check that may only work with one screen size !!!
self.splitter.setSizes([defaultTextEditHeight, 1000])
# Should setStretchFactor be used here ?? This does not seem to work
# self.splitter.setStretchFactor(0, 0)
# self.splitter.setStretchFactor(1, 1)
# What about sizeHint() ?? Should that be used here, and if so, how ??
# set the main form's layout to the QGridLayout
self.gridLayout = QGridLayout()
self.gridLayout.addWidget(self.splitter)
С жестко запрограммированной 1000 и на этом конкретном экране это работает довольно хорошо:
![enter image description here](https://i.stack.imgur.com/55YFz.jpg)
Чтобы повторить (надеюсь более ясно), я пытаюсь удалить жестко запрограммированную 1000 и команду Qt следующим образом:
- Первоначально сделать форма занимает около 2/3 экрана
- Первоначально текстовое поле должно занимать примерно 3 строки текста (минимум 2 строки текста)
- Разрешить пользователю использовать QSplitter изменить размер текстового поля и изображения в любое время и без ограничений
- Когда размер формы изменяется (или уменьшается, или увеличивается), изменяйте размер текстового поля и изображения пропорционально размеру, указанному пользователем во время изменения размера
Я пробовал все комбинации, упомянутые в названии и до сих пор в этом посте, но я не смог получить эту функциональность, за исключением жестко закодированной 1000, которая, вероятно, не будет работать с другим размером экрана.
Как я могу удалить жестко запрограммированную 1000 и изменить вышеперечисленное для достижения предполагаемой функциональности?