Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python QCompleter从多列中选择数据_Python_Pyqt_Pyqt5_Qcompleter - Fatal编程技术网

Python QCompleter从多列中选择数据

Python QCompleter从多列中选择数据,python,pyqt,pyqt5,qcompleter,Python,Pyqt,Pyqt5,Qcompleter,我试图在一行编辑中完成一个补全符,其中一个输入一些字符串,比如firstname、lastname,每个字符串对应于表模型中两列中的一列。最终目标是使顺序灵活,但目前我只希望运行这个命令。目前我尝试的方法是: a将两列的结果合并到一个代理中,即第三列只有firstname,lastname作为离散字符串,如果用户将其作为lastname,firstname输入,则会带来不便。当前的实现不起作用,当我尝试对伪列执行setCompletionColumn时,它不会激活我重新实现的数据方法。colum

我试图在一行编辑中完成一个补全符,其中一个输入一些字符串,比如firstname、lastname,每个字符串对应于表模型中两列中的一列。最终目标是使顺序灵活,但目前我只希望运行这个命令。目前我尝试的方法是:

a将两列的结果合并到一个代理中,即第三列只有firstname,lastname作为离散字符串,如果用户将其作为lastname,firstname输入,则会带来不便。当前的实现不起作用,当我尝试对伪列执行setCompletionColumn时,它不会激活我重新实现的数据方法。columnCount包括伪列tho

b有一个不过滤的补全器,后端代理模型的acceptsrow过滤器在first和last上都不知道如何进行非过滤补全器-否则它只是浏览一列,最后的弹出窗口显示一组没有姓氏的名字

c欺骗一个树模型,并使之成为这样当我放一个逗号时,该模型就会通过一个由所有名字或姓氏以开头的人组成的分支进行查看?前逗号字符串。我只是不知道该如何开始,它使用了与b相同的acceptsrow,但idk如何像单独的~分支那样做~

这让我头疼,而且这些实现都不是特别令人愉快的。我是不是让这件事对自己太难了,好像使用了错误的工具,还是这只是我必须努力去做的事情?我可以粘贴一些代码,但我想知道我所做的是否值得

更新:代码片段和pix

]

红色圆圈就是我所说的多个名字,它们对应于表中的不同条目,但补全符仅限于一列。在点击和获取用户名称方面,我已经大致了解了,这只是格式和处理逗号

以下是我的completer课程的一部分:

 class CustomQCompleter(QCompleter): #dropdown box of suggestions    
    def __init__(self, parent=None,*args):#parent=None):
        self.columnind=0
        super(CustomQCompleter, self).__init__(*args)
        self.parent=parent
        self.setCompletionColumn(self.columnind)
    def pathFromIndex(self,index,role=QtCore.Qt.DisplayRole): #decides what gets put into selection box
        #print(index)
        model=self.source_model
        return model.data(model.index(index.row(),self.columnind),role=QtCore.Qt.DisplayRole)
    def splitPath(self, path):
        self.local_completion_prefix = path #???
        print(path)
        sp=self.local_completion_prefix.split(',')
        if len(sp)>1: #
            print('path split')
            return sp

        return [path]
下面是我重新实现的proxymodel的acceptsrow:

def filterAcceptsRow(self, row_num, parent): #input matches if this returns true       
    self.filterString=self.parent().inp.text()
    self.filterList=[i.strip() for i in self.filterString.split(',')]
    l=len(self.filterList)
    while l<2:#easiest way to get thru this atm, clean up later
        self.filterList.append('')
        l=len(self.filterList)
    if self.baseModel is not None:
        model=self.baseModel
    else:
        model = self.sourceModel()  # the underlying model, 

                      # implmented as a python array

    row = [model.data(model.index(row_num,0)),model.data(model.index(row_num,1))] #gets the data for this row from sql model in list format



    #(row[0] starts with fname and row[1] starts w lname) OR vice versa
    tests=[row[0].startswith(self.filterList[i]) and row[1].startswith(self.filterList[1-i]) for i in [0,1]]
    #tests = len(self.filterSet.intersection(set([row[col] for col in self.filterColumns])))==2
   # print(tests)
    return True in tests   
理想情况下,它看起来像这样:


策略是在创建新角色时使用代理,该角色将返回连接的文本,这样可以看到带有连接文本的弹出窗口,我们将为QCompleter的弹出窗口建立一个自定义委托


你可以更好地解释我,我更了解你想要什么,但我混淆了你的句子:灵活的顺序,这意味着什么?。另一方面,您可以解释它应该如何工作,我认为您在选项中部分地指出了这一点,但目前还不清楚。我理解,当未选择任何文本时,如果我选择其中一个选项,将出现一个包含姓名的弹出窗口,我的名字和姓氏应该一起显示还是一起显示?@eyllanesc“order flexible”在用户中应该能够键入“firstname,lastname”或“lastname,firstname”。现在,弹出窗口是从带有名称的2列表格模型中输入的,因为它一次只能显示一列,所以弹出框只显示名字。我想要的是能够键入某人的姓名,选择他们的全名,并能够返回两列名称。现在我有来自completer的activate fn的ID信号,所以我应该能够找出如何获得一个名称的特定客户ID,现在它只是显示和解析名称,你想要的是使用firstname或lastname进行搜索,并在弹出窗口中显示两个带空格的连接文本,当您从QComboBox中选择一个项目时,QLineEdit必须具有连接的文本。我是对的?你可以展示你的模型,除了展示不同的场景,还有一些图片会有所帮助。嘿,很抱歉缺席。这在很大程度上得到了解决,我遇到的唯一问题是,它不允许lastname逗号firstname,它允许lastname输入,然后选择firstname,我不知道我是否实现了一些错误,但代理似乎没有为我做任何事,我仍然得到了一个名字列表。还有什么想法吗?非常感谢你们迄今为止的帮助:若你们觉得无聊,并没有义务,我会在评论中用几种不同的方式说几次,但互联网并不总是能让你们明白。delegate类与您的类完全相同,只是它有一个打印“测试”,只是因为某种原因它永远不会被激活。除了setcompletionrole和setitemdelegate之外,您还需要什么吗?在画图中,fnok在我的实现中证明了它的作用,可以很好地复制和粘贴您的代码,并打印出“test”。唯一的事情就是弄清楚自己能做到第一、最后和最后,first@user26472Plop,你把我弄糊涂了,更好地解释你的新要求,此外,你不谈论代表,因为根据评论,它工作正常。再给我一点 例如,你想让选项存在吗,安,泰勒和泰勒,安?
import sys

from PyQt5.QtCore import QIdentityProxyModel, Qt
from PyQt5.QtWidgets import QStyledItemDelegate, QCompleter, QApplication, QWidget, \
    QVBoxLayout, QLineEdit, QTableView, QStyleOptionViewItem, QStyle
from PyQt5.QtSql import QSqlDatabase, QSqlQuery, QSqlTableModel

JoinRole = Qt.UserRole +1

class JoinProxyModel(QIdentityProxyModel):
    def __init__(self, columns, *args, **kwargs):
        QIdentityProxyModel.__init__(self, *args, **kwargs)
        self._columns = columns

    def data(self, index, role):
        if role == JoinRole:
            texts = []
            for c in self._columns:
                texts.append(self.sibling(index.row(), c, index.parent()).data())
            return ", ".join(texts)
        return QIdentityProxyModel.data(self, index, role)

class JoinDelegate(QStyledItemDelegate):
    def paint(self, painter, option, index):
        opt = QStyleOptionViewItem(option)
        self.initStyleOption(opt, index)
        opt.text = index.data(JoinRole)
        widget = option.widget
        style = widget.style() if widget else QApplication.style()
        style.drawControl(QStyle.CE_ItemViewItem, opt, painter, widget)


class JoinCompleter(QCompleter):
    def __init__(self, model, columns, parent=None):
        QCompleter.__init__(self, parent)
        # columns: are the columns that are going to concatenate
        proxy = JoinProxyModel(columns)
        proxy.setSourceModel(model)
        self.setModel(proxy)

        self.setCompletionRole(JoinRole)
        self.setFilterMode(Qt.MatchContains)
        self.popup().setItemDelegate(JoinDelegate(self))


def createConnection():
    db = QSqlDatabase.addDatabase("QSQLITE");
    db.setDatabaseName(":memory:")
    if not db.open():
        QMessageBox.critical(nullptr, QObject.tr("Cannot open database"),
            QObject.tr("Unable to establish a database connection.\n"
                        "This example needs SQLite support. Please read "
                        "the Qt SQL driver documentation for information how "
                        "to build it.\n\n"
                        "Click Cancel to exit."), QMessageBox.Cancel)
        return False

    query = QSqlQuery()
    query.exec_("create table person (id int primary key, "
               "firstname varchar(20), lastname varchar(20))")
    query.exec_("insert into person values(101, 'Danny', 'Young')")
    query.exec_("insert into person values(102, 'Christine', 'Holand')")
    query.exec_("insert into person values(103, 'Lars', 'Gordon')")
    query.exec_("insert into person values(104, 'Roberto', 'Robitaille')")
    query.exec_("insert into person values(105, 'Maria', 'Papadopoulos')")

    return True

if __name__ == '__main__':
    app = QApplication(sys.argv)

    if not createConnection():
        sys.exit(-1)

    w = QWidget()

    lay = QVBoxLayout(w)
    le = QLineEdit()
    view = QTableView()
    model = QSqlTableModel()
    model.setTable("person")
    model.select()

    completer = JoinCompleter(model, [1, 2])
    le.setCompleter(completer)
    view.setModel(model)

    lay.addWidget(le)
    lay.addWidget(view)

    w.show()
    sys.exit(app.exec_())