首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QApplication.focusWidget().pos()总是返回0

QApplication.focusWidget().pos()总是返回0
EN

Stack Overflow用户
提问于 2022-06-13 16:32:50
回答 1查看 85关注 0票数 0

我有一个定制的QWidget,我已经嵌入到QTableWidget中了。当我切换QCheckBoxes并修改QLineEdit小部件中的文本时,程序无法将第2行和第1行中的小部件与第0行中的小部件区分开来。如何更改程序,以便打印正在编辑的QLineEdit小部件的正确行和列或正在切换的复选框?

图1在Visual中多次选择第三个复选框后,显示了该程序的屏幕截图和输出。预期输出将重复读取“2.0”,但它将读取“0”。

图2类似地,当我将单元格2,0中的QLineEdit中的文本从“我的自定义文本”修改为“text”时,程序会打印“Handle Cell Edited 0,0,0”,尽管预计它会打印“Handle Cell Edited 2,0 cell 2,0已更改为Text”。

代码:

代码语言:javascript
复制
# Much of this code is copy pasted form user: three_pineapples post on stackoverflow: 
#    https://stackoverflow.com/a/26311179/18914416
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, \
    QApplication, QTableWidgetItem, QLineEdit, QCheckBox
from PyQt5 import QtGui

class SimpleTable(QTableWidget):
    def __init__(self,window):
        # Call the parent constructor
        QTableWidget.__init__(self)
        self.window = window
        

class myWidget(QWidget):
    #This code is adapted paritally form a post by user sebastian at:
    #https://stackoverflow.com/a/29764770/18914416
    def __init__(self,parent=None):
        super(myWidget,self).__init__()
        self.Layout1 = QHBoxLayout()
        self.item = QLineEdit("My custom text")
        #https://stackabuse.com/working-with-pythons-pyqt-framework/
        
        self.Checkbox = QCheckBox()
        self.Checkbox.setCheckState(Qt.CheckState.Unchecked)

        self.Layout1.addWidget(self.Checkbox)
        self.Layout1.addWidget(self.item)
        #https://stackoverflow.com/questions/29764395/adding-multiple-widgets-to-qtablewidget-cell-in-pyqt

        self.item.home(True)
        #https://www.qtcentre.org/threads/58387-Left-text-alignment-for-long-text-on-QLineEdit
        
        self.setLayout(self.Layout1)
        
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout = QHBoxLayout()
        self.setLayout(layout)
        
        self.table_widget = SimpleTable(window=self)
        layout.addWidget(self.table_widget)
        self.table_widget.setColumnCount(3)
        self.table_widget.setHorizontalHeaderLabels(['Colour', 'Model'])

        items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle')]
        for i in range(len(items)):
            c = QTableWidgetItem(items[i][0])
            m = QTableWidgetItem(items[i][1])
             
            self.table_widget.insertRow(self.table_widget.rowCount())
            self.table_widget.setItem(i, 1, c)
            self.table_widget.setItem(i, 2, m)

            myWidget1 = myWidget()
            myWidget1.Checkbox.stateChanged.connect(self.handleButtonClicked)
            myWidget1.item.editingFinished.connect(self.handle_cell_edited)      
            self.table_widget.setCellWidget(i,0,myWidget1)
            myWidget1.Layout1.setContentsMargins(50*i+10,0,0,0)

        self.show()

        self.table_widget.itemChanged.connect(self.handle_cell_edited)


    def handleButtonClicked(self):
        #Adapted from a post by user: Andy at:
        # https://stackoverflow.com/a/24149478/18914416    
        button = QApplication.focusWidget()
        # or button = self.sender()
        index = self.table_widget.indexAt(button.pos())
        if index.isValid():
            print(index.row(), index.column())
    
    # I added this fuction:
    def handle_cell_edited(self):
        if QApplication.focusWidget() != None:
            index = self.table_widget.indexAt(QApplication.focusWidget().pos())
            x,y = index.column(),index.row()
            if index.isValid():
                print("Handle Cell Edited",index.row(), index.column())
            if self.table_widget.item(y,x)!= None:
                print(f"Cell {x},{y} was changed to {self.table_widget.item(y,x).text()}.")

def main():
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())
main()

到目前为止我尝试过的:

我了解到QT有两种类型的小部件可以嵌入到表中;QTableWigetItem可以使用setItem()(3.)插入到表中,Qwidget可以使用setCellWidget()放置到表中。(4.)通常,我知道使用QTableWigetItem one可以设置item.setFlags(Qt.ItemFlag.ItemIsUserCheckable)标志在单元格中创建复选框。(3.)然而,在使用QTableWigetItem时,我无法找到缩进复选框的方法。因为在我的程序上下文中给每个复选框赋予自己的缩进级别很重要,所以我决定在缩进很重要的少数选定单元格中使用Qwidgets而不是QTableWigetItems。我读过,通过创建一个QItemDelegate(5)(6),,您可以通过在框中设置QWidget来做更多的事情。然而,创建一个委托似乎很复杂,所以如果可能的话,我更愿意避免这种情况。如果没有其他方法使程序注册正在编辑的单元格的正确单元号,则创建委托将是我接下来要研究的事情。

对于任何想要在这个应用程序中使用QTableWigetItems的人来说,这里有一个类似的程序,它使用QTableWigetItems而不是QWidgets,但不允许对列0中的文本字段进行单独的缩进或编辑。由于这两个原因之一,QTableWigetItem似乎不能用于列0中的复选框。

使用QTableWidgetItem:的不太成功的尝试

代码语言:javascript
复制
#Much of this code is copy pasted form user: three_pineapples post on stackoverflow:
     #  https://stackoverflow.com/a/26311179/18914416

import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QTableWidget, \
    QApplication, QTableWidgetItem, QLineEdit, QCheckBox
from PyQt5 import QtGui

class SimpleTable(QTableWidget):
    def __init__(self,window):
        QTableWidget.__init__(self)
        self.window = window
        
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        layout = QHBoxLayout()
        self.setLayout(layout)
        
        self.table_widget = SimpleTable(window=self)
        layout.addWidget(self.table_widget)
        self.table_widget.setColumnCount(3)
        self.table_widget.setHorizontalHeaderLabels(['Colour', 'Model'])

        items = [('Red', 'Toyota'), ('Blue', 'RV'), ('Green', 'Beetle')]
        for i in range(len(items)):
            c = QTableWidgetItem(items[i][0])
            m = QTableWidgetItem(items[i][1])
             
            self.table_widget.insertRow(self.table_widget.rowCount())
            self.table_widget.setItem(i, 1, c)
            self.table_widget.setItem(i, 2, m)
            
            item = QTableWidgetItem("My Custom Text")
            item.setFlags(Qt.ItemFlag.ItemIsUserCheckable| Qt.ItemFlag.ItemIsEnabled)
            item.setCheckState(Qt.CheckState.Unchecked)
            self.table_widget.setItem(i,0,item)
            #https://youtu.be/DM8Ryoot7MI?t=251

        self.show()

        #I added this line:
        self.table_widget.itemChanged.connect(self.handle_cell_edited)



    def handleButtonClicked(self):
        #Adapted from a post by user: Andy at:
        # https://stackoverflow.com/a/24149478/18914416    
        button = QApplication.focusWidget()
        # or button = self.sender()
        index = self.table_widget.indexAt(button.pos())
        if index.isValid():
            print(index.row(), index.column())
    
    # I added this fuction:
    def handle_cell_edited(self):
        if QApplication.focusWidget() != None:
            index = self.table_widget.indexAt(QApplication.focusWidget().pos())
            x,y = index.column(),index.row()
            if index.isValid():
                print("Handle Cell Edited",index.row(), index.column())
            if self.table_widget.item(y,x)!= None:
                print(f"Cell {x},{y} was changed to {self.table_widget.item(y,x).text()}.")

def main():
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())
main()

书目:

1.https://i.stack.imgur.com/FudE3.png

2.https://i.stack.imgur.com/C2ypp.png

3.https://youtu.be/DM8Ryoot7MI?t=251

4.https://stackoverflow.com/questions/24148968/how-to-add-multiple-qpushbuttons-to-a-qtableview/24149478#24149478

5.为QWidgets,https://stackoverflow.com/a/35418141/18914416创建一个https://stackoverflow.com/a/35418141/18914416

6.需要创建一个QItemDelegate来向QTableWidgetItemhttps://forum.qt.io/topic/13124/solved-qtablewidgetitem-set-stylesheet添加样式表

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-06-13 17:21:04

小部件的几何形状总是相对于它的父部件。

在第一个示例中,问题是小部件返回的pos()相对于myWidget容器,而且由于垂直位置总是在父级顶部以下几个像素(布局边距),所以总是得到相同的值。

第二个例子有另一个概念上的问题: checkable的复选框不是实际的小部件,所以您得到的小部件就是表本身。

代码语言:javascript
复制
    def handle_cell_edited(self):
        # this will print True
        print(isinstance(QApplication.focusWidget(), QTableWidget))

正如上面所解释的,几何总是相对于父的,所以您实际上将得到表相对于窗口的位置。

第一种情况的解决办法很简单,只要你了解坐标系的相对性。请注意,您不应该依赖focusWidget() (小部件可能不接受焦点),而是实际获取sender(),它是发出信号的对象:

代码语言:javascript
复制
    def handleButtonClicked(self):
        sender = self.sender()
        if not self.table_widget.isAncestorOf(sender):
            return
        # the widget coordinates must *always* be mapped to the viewport
        # of the table, as the headers add margins
        pos = sender.mapTo(self.table_widget.viewport(), QPoint())
        index = self.table_widget.indexAt(pos)
        if index.isValid():
            print(index.row(), index.column())

实际上,这可能并不是必要的,因为如果缩进是惟一的要求,那么项委托就足够了:解决方案是在initStyleOption()中正确地设置initStyleOption()并为缩进使用自定义角色:

代码语言:javascript
复制
IndentRole = Qt.UserRole + 1

class IndentDelegate(QStyledItemDelegate):
    def initStyleOption(self, opt, index):
        super().initStyleOption(opt, index)
        indent = index.data(IndentRole)
        if indent is not None:
            left = min(opt.rect.right(), 
                opt.rect.x() + indent)
            opt.rect.setLeft(left)


class SimpleTable(QTableWidget):
    def __init__(self,window):
        QTableWidget.__init__(self)
        self.window = window
        self.setItemDelegateForColumn(0, IndentDelegate(self))


class Window(QWidget):
    def __init__(self):
        # ...
        for i in range(len(items)):
            # ...
            item.setData(IndentRole, 20 * i)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72606180

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档