在 QDialog 中,调整窗口大小以包含 QTableView 的所有列 [英] In QDialog, resize window to contain all columns of QTableView

查看:96
本文介绍了在 QDialog 中,调整窗口大小以包含 QTableView 的所有列的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个简单的程序来在 QDialog (PySide) 中显示 SQL 数据库表的内容.目标是有一种方法可以扩展窗口以显示所有列,因此用户不必调整大小即可查看所有内容.这个问题是在稍微不同的上下文中解决的:

I am writing a simple program to display the contents of a SQL database table in a QDialog (PySide). The goal is to have a method that expands the window to show all of the columns, so the user doesn't have to resize to see everything. This problem was addressed in a slightly different context:

使 TableView 的宽度适合内容的宽度

基于此,我编写了以下方法:

Based on that, I wrote the following method:

def resizeWindowToColumns(self):
    frameWidth = self.view.frameWidth() * 2
    vertHeaderWidth = self.view.verticalHeader().width()
    horizHeaderWidth =self.view.horizontalHeader().length()
    vertScrollWidth = self.view.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent) 
    fudgeFactor = 6 #not sure why this is needed 
    newWidth = frameWidth + vertHeaderWidth + horizHeaderWidth + vertScrollWidth + fudgeFactor

效果很好.但请注意,我必须添加一个 fudgeFactor.用软糖,它完美地工作.但这表明我已经忘记了六个像素,并且很好奇它们来自哪里.显示多少列或它们各自的宽度似乎并不重要:fudgeFactor 6 似乎总是有效.

It works great. But notice that I have had to add a fudgeFactor. With fudge, it works perfectly. But it suggests I have lost track of six pixels, and am very curious where they are coming from. It doesn't seem to matter how many columns are displayed, or their individual widths: the fudgeFactor 6 always seems to work.

系统详情

Python 2.7 (Spyder/Anaconda).PySide 版本 1.2.2,Qt 版本 4.8.5.带触摸屏的 Windows 7 笔记本电脑(触摸屏有时会在 PySide 中搞砸).

Python 2.7 (Spyder/Anaconda). PySide version 1.2.2, Qt version 4.8.5. Windows 7 laptop with a touch screen (touch screens sometimes screw things up in PySide).

完整的工作示例

# -*- coding: utf-8 -*-
import os
import sys
from PySide import QtGui, QtCore, QtSql

class DatabaseInspector(QtGui.QDialog):

    def __init__(self, tableName, parent = None):
        QtGui.QDialog.__init__(self, parent) 

        #define model
        self.model = QtSql.QSqlTableModel(self)
        self.model.setTable(tableName)
        self.model.select()

        #View of model
        self.view = QtGui.QTableView()
        self.view.setModel(self.model)

        #Sizing
        self.view.resizeColumnsToContents()  #Resize columns to fit content
        self.resizeWindowToColumns()  #resize window to fit columns

        #Quit button
        self.quitButton = QtGui.QPushButton("Quit");
        self.quitButton.clicked.connect(self.reject)

        #Layout
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.view)  #table view
        layout.addWidget(self.quitButton)  #pushbutton
        self.setLayout(layout)
        self.show()  

    def resizeEvent(self, event):  
        #This is just to see what's going on                         
        print "Size set to ({0}, {1})".format(event.size().width(), event.size().height())

    def resizeWindowToColumns(self):
        #Based on: https://stackoverflow.com/a/20807145/1886357
        frameWidth = self.view.frameWidth() * 2
        vertHeaderWidth = self.view.verticalHeader().width()
        horizHeaderWidth =self.view.horizontalHeader().length()
        vertScrollWidth = self.view.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent) 
        fudgeFactor = 6 #not sure why this is needed 
        newWidth = frameWidth + vertHeaderWidth + horizHeaderWidth + vertScrollWidth + fudgeFactor
        if newWidth <= 500:
            self.resize(newWidth, self.height())
        else:
            self.resize(500, self.height())


def populateDatabase():
    print "Populating table in database..."
    query = QtSql.QSqlQuery()
    if not query.exec_("""CREATE TABLE favorites (
                id INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE NOT NULL,
                category VARCHAR(40) NOT NULL,
                number INTEGER NOT NULL,
                shortdesc VARCHAR(20) NOT NULL,
                longdesc VARCHAR(80))"""):
                print "Failed to create table"
                return False
    categories = ("Apples", "Chocolate chip cookies", "Favra beans")
    numbers = (1, 2, 3)
    shortDescs = ("Crispy", "Yummy", "Clarice?")
    longDescs = ("Healthy and tasty", "Never not good...", "Awkward beans for you!")
    query.prepare("""INSERT INTO favorites (category, number, shortdesc, longdesc)
                     VALUES (:category, :number, :shortdesc, :longdesc)""") 
    for category, number, shortDesc, longDesc in zip(categories, numbers, shortDescs, longDescs):
        query.bindValue(":category",  category)
        query.bindValue(":number", number)
        query.bindValue(":shortdesc", shortDesc)
        query.bindValue(":longdesc",  longDesc)        
        if not query.exec_():
            print "Failed to populate table"
            return False 
    return True

def main():
    import site
    app = QtGui.QApplication(sys.argv)

    #Connect to/initialize database
    dbName = "food.db"
    tableName = "favorites"
    site_pack_path = site.getsitepackages()[1]
    QtGui.QApplication.addLibraryPath('{0}\\PySide\\plugins'.format(site_pack_path))
    db = QtSql.QSqlDatabase.addDatabase("QSQLITE")
    fullFilePath = os.path.join(os.path.dirname(__file__), dbName) #;print fullFilePath
    dbExists = QtCore.QFile.exists(fullFilePath) #does it already exist in directory?
    db.setDatabaseName(fullFilePath) 
    db.open()    
    if not dbExists:
        populateDatabase()

    #Display database      
    dataTable = DatabaseInspector(tableName)
    sys.exit(app.exec_())

    #Close and delete database (not sure this is needed)
    db.close()
    del db


if __name__ == "__main__":
    main()

推荐答案

链接问题与您的示例之间的区别在于,前者是在布局中调整小部件的大小,而后者是调整顶级窗口的大小.

The difference between the linked question and your example, is that the former is resizing a widget within a layout, whereas the latter is resizing a top-level window.

顶层窗口通常用框架装饰.在您的系统上,此框架的宽度似乎是每边三个像素,总共六个像素.

A top-level window is usually decorated with a frame. On your system, the width of this frame seems to be three pixels on each side, making six pixels in all.

您可以通过以下方式以编程方式计算此值:

You can calculate this value programmatically with:

    self.frameSize().width() - self.width()

其中 self 是顶级窗口.

然而,可能还有一个额外的问题需要处理,那就是选择何时来计算这个值.在我的 Linux 系统上,在窗口完全显示之前不会绘制框架 - 因此在 __init__ 期间计算不起作用.

However, there may be an extra issue to deal with, and that is in choosing when to calculate this value. On my Linux system, the frame doesn't get drawn until the window is fully shown - so calculating during __init__ doesn't work.

我是这样解决这个问题的:

I worked around that problem like this:

dataTable = DatabaseInspector(tableName)
dataTable.show()
QtCore.QTimer.singleShot(10, dataTable.resizeWindowToColumns)

但我不确定这是否可移植(甚至不一定是最好的方法).

but I'm not sure whether that's portable (or even necessarily the best way to do it).

附注:

似乎后一个问题可能特定于 X11 - 请参阅 Window Geometry 部分.

It seems that the latter issue may be specific to X11 - see the Window Geometry section in the Qt docs.

更新:

以上解释和计算不正确!

The above explanation and calculation is not correct!

窗口装饰仅在定位窗口时相关.resize()setGeometry() 函数总是排除窗口框架,所以在计算总数时不需要考虑它宽度.

The window decoration is only relevant when postioning windows. The resize() and setGeometry() functions always exclude the window frame, so it doesn't need to be factored in when calculating the total width.

在布局中调整小部件大小与调整顶级窗口大小的区别在于后者需要考虑布局边距.

The difference between resizing a widget within a layout versus resizing a top-level window, is that the latter needs to take account of the layout margin.

所以正确的计算是这样的:

So the correct calculation is this:

    margins = self.layout().contentsMargins()
    self.resize((
        margins.left() + margins.right() +
        self.view.frameWidth() * 2 +
        self.view.verticalHeader().width() +
        self.view.horizontalHeader().length() +
        self.view.style().pixelMetric(QtGui.QStyle.PM_ScrollBarExtent)
        ), self.height())

但请注意,这始终为垂直滚动条留出空间.

But note that this always allows room for a vertical scrollbar.

示例脚本没有添加足够的行来显示垂直滚动条,因此在这方面具有误导性 - 如果添加更多行,则总宽度完全正确.

The example script doesn't add enough rows to show the vertical scrollbar, so it is misleading in that respect - if more rows are added, the total width is exactly right.

这篇关于在 QDialog 中,调整窗口大小以包含 QTableView 的所有列的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆