重建一个窗口
Posted
技术标签:
【中文标题】重建一个窗口【英文标题】:Rebuilding a window 【发布时间】:2020-01-18 13:32:06 【问题描述】:我正在使用 PySide2 ,如屏幕截图中所示(您在屏幕截图中看到的是一个示例,Ueli 应用程序启动器,可在 Github 上找到),它是一个应用程序启动器,但由于我对 PySide2 很陌生,所以我很多功能不知道,在这里求助,应该去哪里看看。
我需要什么: 我在文本字段中输入一些内容(在屏幕截图中显示为“测试”的位置),满足我的条件的选项被附加到 UI 中,以便我可以使用箭头键选择它们并按 Enter 键打开/运行程序/文件。 我对所有与 UI 相关的东西都有问题,搜索命令是我已经拥有的东西。
这是我已经拥有的一些代码(用于 Maya,3D 软件):
from PySide2 import QtWidgets, QtCore
from PySide2.QtGui import *
from PySide2.QtWidgets import QDesktopWidget, QScrollArea
from maya import OpenMayaUI
from functools import partial
import sys
try:
from shiboken import wrapInstance
import shiboken
except:
from shiboken2 import wrapInstance
import shiboken2 as shiboken
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
window = OpenMayaUI.MQtUtil.mainWindow()
mayaWindow = shiboken.wrapInstance(long(window), QtWidgets.QMainWindow)
super(MainWindow, self).__init__(mayaWindow)
self.setWindowTitle('Test Window')
self.resize(630, 50);
self.setWindowFlags(QtCore.Qt.Popup | QtCore.Qt.WindowType.NoDropShadowWindowHint)
self.setStyleSheet("background-color: rgb(65, 65, 65);")
# main widget
main_widget = QtWidgets.QWidget(self)
self.setCentralWidget(main_widget)
# layout initialize
self.boxLayout = QtWidgets.QVBoxLayout()
main_widget.setLayout(self.boxLayout)
self.formLayout = QtWidgets.QFormLayout()
# Add Widgets
self.textField = QtWidgets.QLineEdit()
self.textField.setFont(QFont('Helvetica', 16))
self.textField.setStyleSheet("margin: 10px; padding: 10px; \
background-color: \
rgb(40,40,40);\
color: rgb(245,245,245); \
border-style: solid; \
border-radius: 3px; \
border-width: 0.5px; \
border-color: \
rgb(35,35,35);")
self.textField.textChanged.connect(self.searchForCommands)
self.formLayout.addRow(self.textField)
# global layout setting
self.boxLayout.addLayout(self.formLayout)
self.centerWindow()
self.textField.setFocus()
def mousePressEvent(self, QMouseEvent):
xPosition = QMouseEvent.pos().x()
yPosition = QMouseEvent.pos().y()
width = self.width()
height = self.height()
if xPosition > self.width() or xPosition < 0:
self.destroy()
if yPosition > self.height() or yPosition < 0:
self.destroy()
def centerWindow(self):
qRect = self.frameGeometry()
centerPoint = QDesktopWidget().availableGeometry().center()
qRect.moveCenter(centerPoint)
self.move(qRect.topLeft())
def searchForCommands(self):
test = ['Monkey', 'Giraffe', 'Dragon', 'Bull']
#scrollArea = QScrollArea()
#scrollArea.setWidget()
#formLayout.addRow(self.textField)
if self.textField.text().isspace() or self.textField.text() != ' ':
if self.textField.text() == '':
pass
else:
for x in test:
if self.textField.text() in x:
self.formLayout.addRow(QtWidgets.QPushButton(self.textField.text()))
print 'Input: "' + self.textField.text() + '" is in "' + x + '".'
if self.textField.text() == x:
print 'Input: "' + self.textField.text() + '" equals "' + x + '".'
if __name__ == '__main__':
app = QtWidgets.QApplication.instance()
if app is None:
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
#sys.exit(app.exec_())
【问题讨论】:
请尝试更具体。您希望收到什么答复?完成的代码? 【参考方案1】:一种可能的解决方案是创建一个QListView
,并带有一个实现自定义绘画的委托,对于过滤器,您可以使用QSortFilterProxyModel
,如下所示:
import os
import sys
from PySide2 import QtCore, QtGui, QtWidgets
TitleRole = QtCore.Qt.UserRole + 1000
DescriptionRole = QtCore.Qt.UserRole + 1001
IconRole = QtCore.Qt.UserRole + 1002
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
def get_icon_path(name):
return os.path.join(CURRENT_DIR, "img", name)
class FilterProxyModel(QtCore.QSortFilterProxyModel):
def __init__(self, parent=None):
super(FilterProxyModel, self).__init__(parent)
self._filterText = ""
@property
def filterText(self):
return self._filterText
@filterText.setter
def filterText(self, text):
self._filterText = text
self.invalidateFilter()
def filterAcceptsRow(self, sourceRow, sourceParent):
if not self.filterText:
return True
index = self.sourceModel().index(
sourceRow, self.filterKeyColumn(), sourceParent
)
# Returns True if the row must be displayed, otherwise False must be returned.
title = index.data(TitleRole)
description = index.data(DescriptionRole)
return self.filterText.lower() in title.lower()
class StandardItem(QtGui.QStandardItem):
def __init__(self, title="", description="", icon=QtGui.QIcon()):
super(StandardItem, self).__init__()
self.title = title
self.description = description
self.icon = icon
@property
def title(self):
return self.data(TitleRole)
@title.setter
def title(self, title):
self.setData(title, TitleRole)
@property
def description(self):
return self.data(DescriptionRole)
@description.setter
def description(self, description):
self.setData(description, DescriptionRole)
@property
def icon(self):
return self.data(IconRole)
@icon.setter
def icon(self, icon):
self.setData(icon, IconRole)
class StyledItemDelegate(QtWidgets.QStyledItemDelegate):
def sizeHint(self, option, index):
return QtCore.QSize(50, 50)
def paint(self, painter, option, index):
super(StyledItemDelegate, self).paint(painter, option, index)
title = index.data(TitleRole)
description = index.data(DescriptionRole)
icon = index.data(IconRole)
mode = QtGui.QIcon.Normal
if not (option.state & QtWidgets.QStyle.State_Enabled):
mode = QtGui.QIcon.Disabled
elif option.state & QtWidgets.QStyle.State_Selected:
mode = QtGui.QIcon.Selected
state = (
QtGui.QIcon.On
if option.state & QtWidgets.QStyle.State_Open
else QtGui.QIcon.Off
)
iconRect = QtCore.QRect(option.rect)
iconRect.setSize(QtCore.QSize(40, 40))
icon.paint(
painter, iconRect, QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter, mode, state
)
titleFont = QtGui.QFont(option.font)
titleFont.setPixelSize(20)
fm = QtGui.QFontMetrics(titleFont)
titleRect = QtCore.QRect(option.rect)
titleRect.setLeft(iconRect.right())
titleRect.setHeight(fm.height())
color = (
option.palette.color(QtGui.QPalette.BrightText)
if option.state & QtWidgets.QStyle.State_Selected
else option.palette.color(QtGui.QPalette.WindowText)
)
painter.save()
painter.setFont(titleFont)
pen = painter.pen()
pen.setColor(color)
painter.setPen(pen)
painter.drawText(titleRect, title)
painter.restore()
descriptionFont = QtGui.QFont(option.font)
descriptionFont.setPixelSize(15)
fm = QtGui.QFontMetrics(descriptionFont)
descriptionRect = QtCore.QRect(option.rect)
descriptionRect.setTopLeft(titleRect.bottomLeft())
descriptionRect.setHeight(fm.height())
painter.save()
painter.setFont(descriptionFont)
pen = painter.pen()
pen.setColor(color)
painter.setPen(pen)
painter.drawText(
descriptionRect,
fm.elidedText(description, QtCore.Qt.ElideRight, descriptionRect.width()),
)
painter.restore()
class LauncherWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(LauncherWidget, self).__init__(parent)
self.setWindowTitle("Test Window")
self.setStyleSheet("background-color: rgb(65, 65, 65);")
self.releaseKeyboard()
self.textField = QtWidgets.QLineEdit()
self.textField.textChanged.connect(self.onTextChanged)
self.textField.setFont(QtGui.QFont("Helvetica", 16))
self.textField.setStyleSheet(
"margin: 10px; padding: 10px; \
background-color: \
rgb(40,40,40);\
color: rgb(245,245,245); \
border-style: solid; \
border-radius: 3px; \
border-width: 0.5px; \
border-color: \
rgb(35,35,35);"
)
self.model = QtGui.QStandardItemModel(self)
self.proxymodel = FilterProxyModel(self)
self.proxymodel.setSourceModel(self.model)
self.listview = QtWidgets.QListView(
editTriggers=QtWidgets.QAbstractItemView.NoEditTriggers
)
self.listview.setItemDelegate(StyledItemDelegate(self.listview))
self.listview.setModel(self.proxymodel)
self.listview.clicked.connect(self.onClicked)
self.listview.selectionModel().currentChanged.connect(self.resetCurrentIndex)
QtWidgets.QShortcut(
QtGui.QKeySequence(QtCore.Qt.Key_Up), self, activated=self.moveUp
)
QtWidgets.QShortcut(
QtGui.QKeySequence(QtCore.Qt.Key_Down), self, activated=self.moveDown
)
lay = QtWidgets.QVBoxLayout(self)
lay.setContentsMargins(0, 0, 0, 0)
lay.addWidget(self.textField, strecth=1)
lay.addWidget(self.listview, strecth=0)
self.centerWindow()
self.fill_model()
self.resetCurrentIndex()
def fill_model(self):
# https://raw.githubusercontent.com/Bowserinator/Periodic-Table-JSON/master/PeriodicTableJSON.json
for title, description, path_icon in (
(
"Hydrogen",
"Hydrogen is a chemical element with chemical symbol H and atomic number 1. With an atomic weight of 1.00794 u, hydrogen is the lightest element on the periodic table. Its monatomic form (H) is the most abundant chemical substance in the Universe, constituting roughly 75% of all baryonic mass.",
get_icon_path("so-icon.png"),
),
(
"Helium",
"Helium is a chemical element with symbol He and atomic number 2. It is a colorless, odorless, tasteless, non-toxic, inert, monatomic gas that heads the noble gas group in the periodic table. Its boiling and melting points are the lowest among all the elements.",
get_icon_path("so-icon.png"),
),
(
"Lithium",
'Lithium (from Greek:\u03bb\u03af\u03b8\u03bf\u03c2 lithos, "stone") is a chemical element with the symbol Li and atomic number 3. It is a soft, silver-white metal belonging to the alkali metal group of chemical elements. Under standard conditions it is the lightest metal and the least dense solid element.',
get_icon_path("so-icon.png"),
),
(
"Beryllium",
"Beryllium is a chemical element with symbol Be and atomic number 4. It is created through stellar nucleosynthesis and is a relatively rare element in the universe. It is a divalent element which occurs naturally only in combination with other elements in minerals.",
get_icon_path("so-icon.png"),
),
(
"Boron",
"Boron is a metalloid chemical element with symbol B and atomic number 5. Produced entirely by cosmic ray spallation and supernovae and not by stellar nucleosynthesis, it is a low-abundance element in both the Solar system and the Earth's crust. Boron is concentrated on Earth by the water-solubility of its more common naturally occurring compounds, the borate minerals.",
get_icon_path("so-icon.png"),
),
(
"Carbon",
'Carbon (from Latin:carbo "coal") is a chemical element with symbol C and atomic number 6. On the periodic table, it is the first (row 2) of six elements in column (group) 14, which have in common the composition of their outer electron shell. It is nonmetallic and tetravalent\u2014making four electrons available to form covalent chemical bonds.',
get_icon_path("so-icon.png"),
),
(
"Nitrogen",
"Nitrogen is a chemical element with symbol N and atomic number 7. It is the lightest pnictogen and at room temperature, it is a transparent, odorless diatomic gas. Nitrogen is a common element in the universe, estimated at about seventh in total abundance in the Milky Way and the Solar System.",
get_icon_path("so-icon.png"),
),
(
"Oxygen",
"Oxygen is a chemical element with symbol O and atomic number 8. It is a member of the chalcogen group on the periodic table and is a highly reactive nonmetal and oxidizing agent that readily forms compounds (notably oxides) with most elements. By mass, oxygen is the third-most abundant element in the universe, after hydrogen and helium.",
get_icon_path("so-icon.png"),
),
(
"Fluorine",
"Fluorine is a chemical element with symbol F and atomic number 9. It is the lightest halogen and exists as a highly toxic pale yellow diatomic gas at standard conditions. As the most electronegative element, it is extremely reactive:almost all other elements, including some noble gases, form compounds with fluorine.",
get_icon_path("so-icon.png"),
),
(
"Neon",
"Neon is a chemical element with symbol Ne and atomic number 10. It is in group 18 (noble gases) of the periodic table. Neon is a colorless, odorless, inert monatomic gas under standard conditions, with about two-thirds the density of air.",
get_icon_path("so-icon.png"),
),
):
it = StandardItem(
title=title, description=description, icon=QtGui.QIcon(path_icon),
)
self.model.appendRow(it)
@QtCore.Slot()
def resetCurrentIndex(self):
if not self.listview.currentIndex().isValid():
self.listview.setCurrentIndex(self.listview.model().index(0, 0))
@QtCore.Slot()
def moveUp(self):
ix = self.listview.currentIndex()
if ix.row() > 0:
self.listview.setCurrentIndex(ix.sibling(ix.row() - 1, ix.column()))
def moveDown(self):
ix = self.listview.currentIndex()
if ix.row() < (self.listview.model().rowCount() - 1):
self.listview.setCurrentIndex(ix.sibling(ix.row() + 1, ix.column()))
@QtCore.Slot(str)
def onTextChanged(self, text):
self.proxymodel.filterText = text
self.resetCurrentIndex()
@QtCore.Slot(QtCore.QModelIndex)
def onClicked(self, index):
ix = self.proxymodel.mapToSource(index)
it = self.model.itemFromIndex(ix)
if it is None:
return
print("clicked:", it.title, it.description)
def centerWindow(self):
self.setGeometry(
QtWidgets.QStyle.alignedRect(
QtCore.Qt.LeftToRight,
QtCore.Qt.AlignCenter,
self.size(),
QtWidgets.qApp.desktop().availableGeometry(),
)
)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = LauncherWidget()
w.show()
sys.exit(app.exec_())
【讨论】:
我不得不稍微编辑一下代码才能工作,但看起来很棒!我希望您不必为我从头开始编写,我可以使用它,谢谢!以上是关于重建一个窗口的主要内容,如果未能解决你的问题,请参考以下文章