Python QTableWidget не отображает полную ширину - PullRequest
0 голосов
/ 03 ноября 2018

Я опытный (хотя и довольно ржавый) программист Windows. Я пытаюсь создать частичное логическое моделирование компьютера (Ferranti Argus 400), который я разработал в 1963 году (да, я такой старый!

Однако я новичок в программировании на Python, и у меня возникла проблема с форматированием с использованием QTableWidget.

Я хочу отобразить это справа рядом с набором элементов управления для ввода тестовых данных для имитируемой функции (и использовать QTableWidget для отображения шагов, к которым будет выполняться симуляция), например, показать работу бита множителя по доле

Я пытаюсь использовать QHBoxLayout () в качестве внешнего контейнера с двумя встроенными ящиками. Левый QVBox будет содержать мою запись данных для симуляции, а правый блок будет содержать объект QTablewidget с прокруткой, отображающей состояние компьютерных регистров.

QTableWidget работает (приведенный ниже является упрощением), пока я не добавлю Vbox слева, который содержит элементы управления (один набор включен здесь). Стол сжимается от полной ширины и располагается справа от оставшегося пространства. Я хотел бы, чтобы он находился слева от других элементов управления и чтобы он прокручивался, если недостаточно места (целевая машина имеет 32 * 24-битные регистры для отображения, хотя сначала я буду тестировать с 8 битами)

Экран с группой слева

введите описание изображения здесь

class App(QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 simple window'

        self.left = 10
        self.top = 50
        self.width = 800
        self.height = 480

        self.initUI()

        def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Parent layout
        self.central_Widget = QWidget(self)
        self.setCentralWidget(self.central_Widget)
        self.central_Layout = QHBoxLayout()

        # Configure left panel as Vbox
        self.leftpanel_Layout = QVBoxLayout()
        #
        self.leftpanel_Layout.addWidget(DataSelectionGroup("Data entry mode"))
        #
        # Add stretch to bottom of panel
        self.leftpanel_Layout.addStretch(0)

        self.rightpanel_Layout = QVBoxLayout()
        self.myLogTable = LogTablex()
        self.rightpanel_Layout.addWidget(self.myLogTable)

        self.setLayout(self.rightpanel_Layout)


        # Add left panel layout to central layout
   # uncomment these lines to see the unwanted behaviour
        #self.central_Layout.addLayout(self.leftpanel_Layout)
        #self.central_Layout.addStretch(0)

        self.setLayout(self.central_Layout)

        self.central_Layout.addLayout(self.rightpanel_Layout)
        self.setLayout(self.central_Layout)

        self.central_Widget.setLayout(self.central_Layout)
        self.setWindowTitle("Demo")
        self.show()


class DataSelectionGroup(QGroupBox):
    """ Create a group of Radio Buttons to choose type of data entry """
    def __init__(self, title):
        super().__init__(title)

        self.buttonLayout = QVBoxLayout()

        # add radio buttons to choose which mode of data entry to use
        self.radio1 = QRadioButton("&Binary")
        self.buttonLayout.addWidget(self.radio1)
        self.radio1.setChecked(True)

        self.radio2 = QRadioButton("Decimal &Fraction")
        self.buttonLayout.addWidget(self.radio2)

        self.radio3 = QRadioButton("Decimal &Integer")
        self.buttonLayout.addWidget(self.radio3)

        self.setLayout(self.buttonLayout)

class LogTablex(QTableWidget):
    def __init__(self, WordLength:int = 24):
        super().__init__()

        self.WordLength = WordLength
        self.initTable(["Note", "X", "Q", "N", "C", "O"])

    def initTable(self, headerlist):
        font = QFont()
        font.setFamily = "Courier New"
        font.setPointSize(8)

        self.setFont(font)
        self.horizontalHeader().setStyleSheet("QHeaderView::section { background-color:lightgrey; }")

        self.setColumnCount(len(headerlist))
        self.setHorizontalHeaderLabels(headerlist)

        self.setRowCount(0)
        self.start_newrow()
        self.str = '0' * self.WordLength + ' '

        self.setCellWidget(0, 0, QLabel("note"))
        self.setCellWidget(0, 1, QLabel(self.str))
        self.setCellWidget(0, 2, QLabel(self.str))
        self.setCellWidget(0, 3, QLabel(self.str))
        self.setCellWidget(0, 4, QLabel("1"))
        self.setCellWidget(0, 5, QLabel("1"))

        self.verticalHeader().setDefaultSectionSize(22)
        self.horizontalHeader().setSectionResizeMode(3)

        self.resizeColumnsToContents()

    def start_newrow(self, note:str = "new note         "):
        self.insertRow(self.rowCount())
        self.setCellWidget(self.rowCount() - 1, 0, QLabel(note))


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

Эта версия производит первое изображение. Если вы раскомментируете две показанные строки, появится вторая версия. Я боролся с этим некоторое время, и я не могу понять, как заставить правую руку вести себя. Я надеюсь, что кто-то может пролить свет на это.

Я использую PyQt5 с последней версией Python, загруженной около 1 недели назад. Я работаю на Windows 10.

Это мой первый пост здесь. Надеюсь он отформатирован правильно

1 Ответ

0 голосов
/ 03 ноября 2018

Прежде всего, я рекомендую вам выполнить скрипт в CMD или терминале, потому что во многих случаях среды IDE скрывают нам ошибки, например, если я выполняю ваш код, я получаю следующее сообщение:

QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout
QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout
QWidget::setLayout: Attempting to set QLayout "" on App "", which already has a layout

И эта ошибка, потому что QMainWindow - это специальный виджет с предустановленным макетом, как показано на следующем рисунке:

enter image description here

И в вашем случае вы пытаетесь заменить его, правильная вещь - установить макет на центральный виджет.

Возвращаясь к проблеме, кажется, что вы постоянно добавляете макеты, и это вызывает проблему, поэтому я улучшил ваш код для определения позиций (я рекомендую не делать атрибуты макетов класса, поскольку они обычно не используются повторно)

from PyQt5 import QtCore, QtGui, QtWidgets


class App(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 simple window'
        self.left, self.top, self.width, self.height = 10, 50, 800, 480
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # Parent layout
        self.central_Widget = QtWidgets.QWidget()
        self.setCentralWidget(self.central_Widget)
        central_Layout = QtWidgets.QHBoxLayout(self.central_Widget)

        leftpanel_Layout = QtWidgets.QVBoxLayout()
        leftpanel_Layout.addWidget(DataSelectionGroup("Data entry mode"))
        leftpanel_Layout.addStretch()

        rightpanel_Layout = QtWidgets.QVBoxLayout()
        self.myLogTable = LogTablex()
        rightpanel_Layout.addWidget(self.myLogTable)

        central_Layout.addLayout(leftpanel_Layout)
        central_Layout.addLayout(rightpanel_Layout)
        self.setWindowTitle("Demo")
        self.show()


class DataSelectionGroup(QtWidgets.QGroupBox):
    """ Create a group of Radio Buttons to choose type of data entry """
    def __init__(self, title):
        super().__init__(title)
        buttonLayout = QtWidgets.QVBoxLayout(self)
        # add radio buttons to choose which mode of data entry to use
        self.radio1 = QtWidgets.QRadioButton("&Binary")
        buttonLayout.addWidget(self.radio1)
        self.radio1.setChecked(True)
        self.radio2 = QtWidgets.QRadioButton("Decimal &Fraction")
        buttonLayout.addWidget(self.radio2)
        self.radio3 = QtWidgets.QRadioButton("Decimal &Integer")
        buttonLayout.addWidget(self.radio3)


class LogTablex(QtWidgets.QTableWidget):
    def __init__(self, WordLength:int = 24):
        super().__init__()
        self.WordLength = WordLength
        self.initTable(["Note", "X", "Q", "N", "C", "O"])

    def initTable(self, headerlist):
        font = QtGui.QFont("Courier New", 8)
        self.setFont(font)
        self.horizontalHeader().setStyleSheet("QHeaderView::section { background-color:lightgrey; }")
        self.setColumnCount(len(headerlist))
        self.setHorizontalHeaderLabels(headerlist)
        self.setRowCount(0)
        self.start_newrow()

        text = '0' * self.WordLength + ' '
        for i, val in enumerate(("note", text, text, text, "1", "1",)):
            self.setCellWidget(0, i, QtWidgets.QLabel(val))

        self.verticalHeader().setDefaultSectionSize(22)
        self.horizontalHeader().setSectionResizeMode(3)
        self.resizeColumnsToContents()

    def start_newrow(self, note: str = "new note         "):
        self.insertRow(self.rowCount())
        self.setCellWidget(self.rowCount() - 1, 0, QtWidgets.QLabel(note))


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())

enter image description here

Обновление:

Чтобы первый макет занимал минимальное пространство, а второй расширялся, при добавлении rightpanel_Layout необходимо добавить растяжку 1, поэтому измените ее на:

central_Layout.addLayout(leftpanel_Layout)
central_Layout.addLayout(rightpanel_Layout, stretch=1) # <---

Также нет необходимости устанавливать фиксированные анкеры, макеты сделают работу за вас:

class DataEntryGroupLayout(QtWidgets.QGroupBox):
    def __init__(self, title):
        super().__init__(title)
        _form = QtWidgets.QFormLayout(self)
        # Add the form controls to the group box = list required
        _pairlist = ["x value", "n value"]
        for _pair in _pairlist:
            _label = QtWidgets.QLabel(_pair)
            _value = QtWidgets.QLineEdit()
            _form.addRow(_label, _value)

enter image description here

...