2

特定の状況で、タイトルのすべてのものを連携させる方法を考え出すのに苦労しています。ここでは PyQt5 を使用していますが、非常に簡単に翻訳できるので、通常の C++ Qt で応答してください。

私は次のUIを作成しようとしています:

  • メイン フォーム ( から継承しQWidget、 を使用することもできますQMainWindow)

  • メイン フォームには、上部に が含まれ、残りのスペースを占有する画像を表示するカスタム クラス ( から継承) を含むQSplitter垂直方向の が含まれている必要があります。QTextEditQLabel

  • 上部のQTextEditはデフォルトで約 3 行のテキストの高さに設定する必要がありますが、これはQSplitter.

  • カスタム クラスは、アスペクト比を維持しながら、使用可能なスペースを考慮して、できるだけ大きくなるように画像のサイズを変更する必要があります。

もちろん、トリッキーな部分は、ユーザーのモニターの大きさとフォームの移動方法に応じて、すべてを正しくサイズ変更することです。これは、幅が約 1,000 px の小さな画面で実行する必要があり、おそらく 3,000 px 以上の幅の画面で実行する必要があります。

これが私がこれまでに持っているものです:

# 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()

現在、私は2560x1440の画面でテストしており、魔法を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 を使用すると、この特定の画面ではかなりうまく機能します。

ここに画像の説明を入力

繰り返しますが (できればもっと明確に)、次のようにハードコードされた 1000 とコマンド Qt を削除できるようにしようとしています。

  • 最初に、フォームが画面の約 2/3 を占めるようにします。
  • 最初に、テキスト ボックスを約 3 行のテキストの高さにします (最小で 2 行のテキストの高さ)。
  • ユーザーが QSplitter を使用して、テキスト ボックスと画像のサイズをいつでも無制限に変更できるようにする
  • フォームのサイズが変更された (または最小化または最大化された) 場合、テキスト ボックスと画像のサイズを、ユーザーがサイズ変更時にどのように持っていたかに比例してサイズ変更します。

タイトルとこれまでの投稿で言及されているもののすべての組み合わせを試しましたが、おそらく別の画面サイズでは機能しないハードコードされた 1000 を除いて、この機能を取得できませんでした.

ハードコーディングされた 1000 を削除し、上記を変更して意図した機能を実現するにはどうすればよいですか?

4

1 に答える 1