简体   繁体   English

Qt 小部件可以是复选框或文本,具体取决于初始值

[英]Qt widget that can be either checkbox or text depending on initial value

I'm trying to figure out how to make a widget that would merge QCheckBox with QLineEdit into one.我试图弄清楚如何制作一个将 QCheckBox 与 QLineEdit 合并为一个的小部件。

In my interface, I parse attributes that can be either booleans or something else and I need to display them for users to edit.在我的界面中,我解析可以是布尔值或其他属性的属性,我需要显示它们以供用户编辑。 This means I have a fair bit of IFs in the code and I would like to encapsulate the logic into a widget.这意味着我在代码中有相当多的 IF,我想将逻辑封装到一个小部件中。 My very naive implementation looks like this but it is not a true widget and this class requires special handling in the UI.我非常天真的实现看起来像这样,但它不是一个真正的小部件,这个类需要在 UI 中进行特殊处理。 How can I make it a normal widget that can be used in any interface like all native widgets?我怎样才能使它成为一个普通的小部件,可以像所有原生小部件一样在任何界面中使用?

from Qt import QtWidgets, QtCore


class SettingWidget(QtWidgets.QWidget):
    '''a simple widget that can be either a bool or string. not sure how to make it an actual widget and this is just a wrapper'''

    changed = QtCore.Signal(str, object)

    def __init__(self, name, value):
        super(self.__class__, self).__init__()
        self.name = name

        if isinstance(value, bool):
            self.w_value = QtWidgets.QCheckBox()
            self.w_value.stateChanged.connect(self._checkboxChanged)
            self.w_value.setChecked(value)
            self.changed.emit(self.name, value)
        else:
            self.w_value = QtWidgets.QLineEdit()
            self.w_value.textChanged.connect(self._textChanged)
            self.w_value.setText(str(value))
            self.changed.emit(self.name, str(value))

    def _checkboxChanged(self, state):
        if state == QtCore.Qt.Checked:
            self.changed.emit(self.name, True)
        else:
            self.changed.emit(self.name, False)

    def _textChanged(self, text):
        self.changed.emit(self.name, str(text))

    def getWidget(self):
        return self.w_value

A possible solution is to use SettingWidget as a container for one of the other widgets and then set it through a layout:一种可能的解决方案是使用 SettingWidget 作为其他小部件之一的容器,然后通过布局设置它:

lay = QtWidgets.QHBoxLayout(self)
lay.addWidget(self.w_value)

But IMO a better design is to create a mixin and design a function that provides the widget.但是 IMO 更好的设计是创建一个 mixin 并设计一个提供小部件的功能。

from Qt import QtCore, QtWidgets


class SettingMixin:
    changed = QtCore.Signal(str, object)

    def __init__(self, name):
        self._name = name

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, name):
        self._name = name

    def handle_changed(self, value):
        self.changed.emit(self.name, value)


class SettingCheckBox(QtWidgets.QCheckBox, SettingMixin):
    def __init__(self, name, initial_value, parent=None):
        super().__init__(parent)
        self.name = name
        self.setChecked(initial_value)
        self.toggled.connect(self.handle_changed)


class SettingLineEdit(QtWidgets.QLineEdit, SettingMixin):
    def __init__(self, name, initial_value, parent=None):
        super().__init__(parent)
        self.name = name
        self.setText(initial_value)
        self.textChanged.connect(self.handle_changed)


def build_setting_widget(name, initial_value):
    if isinstance(initial_value, bool):
        return SettingCheckBox(name, initial_value)
    elif isinstance(initial_value, str):
        return SettingLineEdit(name, initial_value)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)
    widget = QtWidgets.QWidget()
    lay = QtWidgets.QHBoxLayout(widget)

    w1 = build_setting_widget("Foo", True)
    w1.changed.connect(print)

    w2 = build_setting_widget("Bar", "Hello World")
    w2.changed.connect(print)

    lay.addWidget(w1)
    lay.addWidget(w2)
    widget.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM