我正在编写一个简单的程序来在QDialog(PySide)中显示SQL数据库表的内容。目标是有一个扩展窗口以显示所有列的方法,因此用户不必调整大小以查看所有内容。在稍微不同的背景下解决了这个问题:
Fit width of TableView to width of content
基于此,我写了以下方法:
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似乎总能工作。
系统详情
Python 2.7(Spyder / Anaconda)。 PySide版本1.2.2,Qt版本4.8.5。带触摸屏的Windows 7笔记本电脑(触摸屏有时会在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()
答案 0 :(得分:2)
链接问题与您的示例之间的区别在于,前者是在布局中调整窗口小部件的大小,而后者是调整顶级窗口的大小。
顶级窗口通常用框架装饰。在你的系统上,这个帧的宽度似乎是每边三个像素,总共六个像素。
您可以使用以下方式以编程方式计算此值:
self.frameSize().width() - self.width()
其中self
是顶级窗口。
但是,可能还有一个额外的问题需要处理,那就是选择时来计算这个值。在我的Linux系统上,框架在窗口完全显示之前不会被绘制 - 所以在__init__
期间计算不起作用。
我解决了这个问题:
dataTable = DatabaseInspector(tableName)
dataTable.show()
QtCore.QTimer.singleShot(10, dataTable.resizeWindowToColumns)
但我不确定这是否可移植(或者甚至是最好的方式)。
<强> PS 强>:
似乎后一个问题可能特定于X11 - 请参阅Qt文档中的Window Geometry部分。
<强>更新强>:
上述说明和计算不正确!
窗口装饰仅在位置窗口时相关。 resize()
和setGeometry()
函数始终排除窗口框架,因此在计算总宽度时不需要考虑它。
在布局中调整窗口小部件的大小与调整顶级窗口的大小之间的区别在于,后者需要考虑布局边距。
所以正确的计算是:
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())
但请注意,这总是允许空间用于垂直滚动条。
示例脚本没有添加足够的行来显示垂直滚动条,因此在这方面会产生误导 - 如果添加更多行,则总宽度完全正确。