如何动态地将 QtCore.Qt.MatchgFlag 组合在一起而不是硬编码它们

问题描述 投票:0回答:1

DemoUI Front End

我正在尝试编写一个小应用程序来使用字典来控制 FastAPI 服务器的配置。由于我正在使用 QTreeView,并且想创建一个搜索框来输入字典键的文本值,并要求 GUI 应用程序展开键,并突出显示感兴趣的键、值对,所以我可以仅跳转到编辑和更改配置。有一个搜索MatchFlag,但我不知道它在C++端是如何实现的,这个MatchFlag的行为不像Python 3.9 Flag类,所以我用这个包装:

import re
from enum import Enum, Flag
from PyQt5 import QtCore
from collections import OrderedDict
from definition import Definitions as df
import logging

class GUIMatchFlag(Flag):
    SelectSearchOptions = -1
    MatchWrap = QtCore.Qt.MatchFlag.MatchWrap
    MatchRecursive = QtCore.Qt.MatchFlag.MatchRecursive
    MatchContains = QtCore.Qt.MatchFlag.MatchContains
    MatchExactly = QtCore.Qt.MatchFlag.MatchExactly
    MatchStartsWith = QtCore.Qt.MatchFlag.MatchStartsWith
    MatchEndsWith = QtCore.Qt.MatchFlag.MatchEndsWith
    MatchRegularExpression = QtCore.Qt.MatchFlag.MatchRegularExpression
    MatchWildcard = QtCore.Qt.MatchFlag.MatchWildcard
    MatchFixedString = QtCore.Qt.MatchFlag.MatchFixedString
    MatchCaseSensitive = QtCore.Qt.MatchFlag.MatchCaseSensitive

    # flag_list = None

    @classmethod
    def splitTitleChar(cls, txt: str, is_name_only=False):
        new_txt = re.sub(r'([a-z])([A-Z)])', r'\1 \2', txt)
        new_txt = (new_txt.split('.')[1] if is_name_only else new_txt)
        return new_txt


    @classmethod
    def getFlagDict(cls, is_name_only=False):
        attrib_name = ("name_only_flag_list" if is_name_only else "flag_list")
        is_init = not hasattr(cls, attrib_name)
        if is_init:
            flag_dict = OrderedDict()
            for item in GUIMatchFlag:
                split_name = cls.splitTitleChar(str(item), is_name_only=is_name_only)
                entry = {split_name: item.value}
                flag_dict.update(entry)
            setattr(cls, attrib_name, flag_dict)
        return getattr(cls, attrib_name)

    @classmethod
    def getQtFlagValue(cls, flag_name: str, is_name_only=False):
        name_to_find = cls.splitTitleChar(flag_name)
        flag_dict = cls.getFlagDict(is_name_only=is_name_only)
        find_value = flag_dict[name_to_find]
        return find_value

    @classmethod
    def getIndexForName(cls, flag_name: str, is_name_only=False):
        flag_dict = cls.getFlagDict(is_name_only=is_name_only)
        name_index_list = [(name, index) for (index, (name, value)) in enumerate(flag_dict.items()) if (name == flag_name)]
        return name_index_list[0][1]

    @classmethod
    def getQtComposeFlagValues(cls, flag_list: list[str]):
        logger.info(f'flag_list:{flag_list}')
        # local_list = [
        #     QtCore.Qt.MatchFlag.MatchWrap,
        #     QtCore.Qt.MatchFlag.MatchRecursive,
        #     QtCore.Qt.MatchFlag.MatchContains,
        #     QtCore.Qt.MatchFlag.MatchExactly,
        #     QtCore.Qt.MatchFlag.MatchStartsWith,
        #     QtCore.Qt.MatchFlag.MatchEndsWith,
        #     QtCore.Qt.MatchFlag.MatchRegularExpression,
        #     QtCore.Qt.MatchFlag.MatchWildcard,
        #     QtCore.Qt.MatchFlag.MatchFixedString,
        #     QtCore.Qt.MatchFlag.MatchCaseSensitive,
        # ]

        compose_flag = None
        for index, flag_entry in enumerate(flag_list):
            (flag_name, flag_val) = flag_entry
            # local_list_index = cls.getIndexForName(flag_name, is_name_only=True)
            # local_list_index -= 1
            # actual_flag_val = local_list[local_list_index]
            is_first = (index == 0)
            if is_first:
                compose_flag = flag_val
            else:
                compose_flag |= flag_val
        return compose_flag

每当“按下”事件触发时,我都会调用此函数来更新标志:

    def searchOptionChanged(self, item:QStandardItem, is_checked: bool=False):
        item_txt = item.text()
        if not is_checked:
            try:
                del self.search_option_flag_checked_dict[item_txt]
                logger.info(f'Removing item {item_txt}')
            except KeyError as e:
                logger.info(f'Removing item {item_txt} causing exception: {e}')
        else:
            flag_dict = GUIMatchFlag.getFlagDict(is_name_only=True)
            search_flag_value = flag_dict[item_txt]
            new_search_flag_entry = {item_txt: search_flag_value}
            self.search_option_flag_checked_dict.update(new_search_flag_entry)

        flag_list = list(self.search_option_flag_checked_dict.items())
        logger.info(f'flag_list {flag_list}')
        self.search_option_flag = GUIMatchFlag.getQtComposeFlagValues(flag_list=flag_list)
        logger.info(f'search_option_flag: {self.search_option_flag}')

这是我的 CheckableCombobox

from definition import Definitions as df

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from typing import Callable
from typing import Iterable
from collections import OrderedDict
import logging

logger = logging.getLogger(df.LOGGING_NAME)

class CheckableComboBox(QComboBox):
    # constructor
    def __init__(self, parent=None, item_pressed_action: Callable=None):
        super(CheckableComboBox, self).__init__(parent)
        # self.setMinimumWidth(200)
        self.setMinimumContentsLength(25)
        self.setSizeAdjustPolicy(QComboBox.AdjustToContentsOnFirstShow)
        self.view().pressed.connect(self.itemPressedAction)
        self.model = QStandardItemModel(self)
        # model.itemChanged.connect(item_pressed_action)
        self.item_pressed_action = item_pressed_action
        self.setModel(self.model)
        self.item_dict = None


    # action called when item get checked
    def do_action(self, item: QStandardItem, is_checked: bool=False):
        item_text = item.text()
        state_msg = (f'{item_text} is ' + "On" if is_checked else "Off")
        logger.info(state_msg)
        # when any item get pressed

    # def setOptionByList(self, flag_list: list[MatchFlag]):
    #     self.model()
    #     for flag in flag_list:
    #
    #         item: QStandardItem = self.model().itemFromIndex(index)
    #         is_checked = (item.checkState() == QtCore.Qt.CheckState.Checked)
    #         new_state = (QtCore.Qt.CheckState.Unchecked if is_checked else QtCore.Qt.CheckState.Checked)
    #         item.setCheckState(new_state)

    def addItems(self, item_list:Iterable, ip_str=None):
        self.item_dict = OrderedDict(item_list)
        for (k, v) in self.item_dict.items():
            self.addItem(k)
        first_index: QModelIndex = self.model.index(0, 0)
        first_item: QStandardItem = self.model.itemFromIndex(first_index)
        first_item.setSelectable(False)

    def itemPressedAction(self, index: QModelIndex):
        # getting the item
        item: QStandardItem = self.model.itemFromIndex(index)

        is_first_item = index.row() == 0
        if is_first_item:
            item.setCheckState(QtCore.Qt.CheckState.Unchecked)
            return

        item: QStandardItem = self.model.itemFromIndex(index)
        old_state = item.checkState()
        is_checked = (old_state == QtCore.Qt.CheckState.Checked)
        new_state = (QtCore.Qt.CheckState.Unchecked if is_checked else QtCore.Qt.CheckState.Checked)

        item.setCheckState(new_state)

        is_checked = (new_state == QtCore.Qt.CheckState.Checked)
        logger.info(f'{item.text()} pressed, is_checked: {is_checked}, old_state:{old_state}, new_state:{new_state}')
        # call the action
        has_external_action = (self.item_pressed_action is not None)
        if has_external_action:
            self.item_pressed_action(item, is_checked)
        else:
            self.do_action(item, is_checked)

我不明白的是,虽然值是相同的,但当它传递给搜索函数时:

    def searchModelUsingName(self, search_text: QVariant, search_flag: Qt.MatchFlag):
        pattern = df.makePattern(search_text, flags=re.I)

        test_flags = GUIMatchFlag.MatchContains.value | GUIMatchFlag.MatchWrap.value | GUIMatchFlag.MatchRecursive.value
        # search_text = "GitExec"
        local_search_flag = Qt.MatchFlag.MatchContains | Qt.MatchFlag.MatchWrap | Qt.MatchFlag.MatchRecursive #::MatchContains | Qt::MatchWrap | Qt::MatchRecursive
        is_equal = (local_search_flag == test_flags)
        is_equal_search_flag = (local_search_flag == search_flag)
        logger.info(f'test_flags == local_search_flag => is_equal:{is_equal}, is_equal_search_flag:{is_equal_search_flag}')
        model: JsonModel = self.model
        is_valid_index = self.currentIndex().isValid()

        search_start_index: QModelIndex = (self.currentIndex() if is_valid_index else model.index(0, 0))
        next_matches = model.match(search_start_index,
                                   Qt.ItemDataRole.DisplayRole,
                                   search_text,
                                   1,
                                   local_search_flag
                                   )  # supposed to be QList<QModelIndex>, or QModelIndexList
        is_found = len(next_matches) > 0
        if not is_found:
            return

        select_model: QItemSelectionModel = self.selectionModel()
        select_list: list = self.selectionModel().selectedIndexes()
        select_model.clearSelection()
        found_index: QModelIndex = None
        for found_index in next_matches:
            item_found: TreeItem = found_index.internalPointer()
            item_info: ItemInfo = item_found.getItemInfoRecord()
            tree_root: dict = item_info.root
            key_list = item_info.key_list
            key_list.reverse()
            first_level_key = key_list[0]
            has_second_key = len(key_list) > 1
            second_level_key = None
            if has_second_key:
                second_level_key = key_list[1]

            first_parent_item: TreeItem = tree_root[first_level_key]
            first_parent_item_index: QModelIndex = model.getNodeByKey(first_level_key)
            is_expanding = not self.isExpanded(first_parent_item_index)
            if is_expanding:
                self.setExpanded(first_parent_item_index, True)
            # select_model.select(first_parent_item, QItemSelectionModel.Select | QItemSelectionModel.Rows)

            if has_second_key:
                second_parent_item: TreeItem = model.getNodeByKey(second_level_key, first_parent_item_index)
                is_expanding = not self.isExpanded(second_parent_item)
                if is_expanding:
                    self.setExpanded(second_parent_item, True)
                # select_model.select(second_parent_item, QItemSelectionModel.Select | QItemSelectionModel.Rows)
            # else:
            #     select_model.select(first_parent_item, QItemSelectionModel.Select | QItemSelectionModel.Rows)
            select_model.select(found_index, QItemSelectionModel.Select | QItemSelectionModel.Rows)

动态组合标志不等于硬编码组合标志。在上面的代码中,它总是说 False,尽管我将相同的标志标记为硬编码标志。有人可以帮我解释为什么会出现这种情况吗?我正在使用Qt5

我期望硬编码的 ORred 标志和动态 ORred 标志相等

python python-3.x pyqt5
1个回答
0
投票

非常感谢您的回答。我已按照您的指示将代码更改为

@classmethod
def getQtComposeFlagValues(cls, flag_list: list[str]):
    logger.info(f'flag_list:{flag_list}')
    compose_flag = None
    for index, flag_entry in enumerate(flag_list):
        (flag_name, flag_val) = flag_entry
        is_first = (index == 0)
        if is_first:
            compose_flag = QtCore.Qt.MatchFlag(flag_val)
        else:
            compose_flag |= QtCore.Qt.MatchFlag(flag_val)
    return compose_flag

但是,当我运行代码时,compose_flag 的类型转换仍然不等于硬编码的 OR 标志。比较仍然显示错误。

© www.soinside.com 2019 - 2024. All rights reserved.