swipe to check/uncheck in QListWidget - python

I would like to set a QListWidget in PyQt5 to check or uncheck the check boxes when I swipe.
Here is my interface:
And my code:
import sys
from PyQt5.QtCore import QDate, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super(VerifyDialog, self).__init__(parent)
self.listWidget = QListWidget()
for i in range(100):
item = QListWidgetItem("Item %i" % i)
# could be Qt.Unchecked; setting it makes the check appear
item.setCheckState(Qt.Checked)
self.listWidget.addItem(item)
runButton = QPushButton("Run")
runButton.clicked.connect(self.exec)
cancelButton = QPushButton("Cancel")
cancelButton.clicked.connect(self.close)
horizontalLayout = QHBoxLayout()
horizontalLayout.addWidget(self.listWidget, 1)
buttonsLayout = QHBoxLayout()
buttonsLayout.addStretch(1)
buttonsLayout.addWidget(runButton)
buttonsLayout.addWidget(cancelButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(horizontalLayout)
mainLayout.addSpacing(12)
mainLayout.addLayout(buttonsLayout)
self.setLayout(mainLayout)
self.setWindowTitle("Config Dialog")
self.show()
if __name__=="__main__":
app = QApplication(sys.argv)
dialog = VerifyDialog()
sys.exit(app.exec_())
I want to click on Item 4 and have it uncheck (it's easier than clicking the box), and then I want to drag down and have lots of other items uncheck.

You must use the itemEntered signal that sends you the object under the mouse.
self.listWidget.itemEntered.connect(lambda item: item.setCheckState(Qt.Checked if item.checkState()==Qt.Unchecked else Qt.Unchecked))
Complete code:
import sys
from PyQt5.QtCore import QDate, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class VerifyDialog(QDialog):
def __init__(self, parent=None):
super(VerifyDialog, self).__init__(parent)
self.listWidget = QListWidget()
self.listWidget.itemEntered.connect(lambda item: item.setCheckState(Qt.Checked if item.checkState()==Qt.Unchecked else Qt.Unchecked))
for i in range(100):
item = QListWidgetItem("Item %i" % i)
# could be Qt.Unchecked; setting it makes the check appear
item.setCheckState(Qt.Checked)
self.listWidget.addItem(item)
runButton = QPushButton("Run")
runButton.clicked.connect(self.exec)
cancelButton = QPushButton("Cancel")
cancelButton.clicked.connect(self.close)
horizontalLayout = QHBoxLayout()
horizontalLayout.addWidget(self.listWidget, 1)
buttonsLayout = QHBoxLayout()
buttonsLayout.addStretch(1)
buttonsLayout.addWidget(runButton)
buttonsLayout.addWidget(cancelButton)
mainLayout = QVBoxLayout()
mainLayout.addLayout(horizontalLayout)
mainLayout.addSpacing(12)
mainLayout.addLayout(buttonsLayout)
self.setLayout(mainLayout)
self.setWindowTitle("Config Dialog")
self.show()
if __name__=="__main__":
app = QApplication(sys.argv)
dialog = VerifyDialog()
sys.exit(app.exec_())

Related

How to open a new MDI sub-window in PyQt5?

What I want to do is to open a new Countrypage sub-window by clicking on the "New" button which is in Countrypage itself.
For example, if I click the "New" button in a CountryPage window (window title: "Country page"), one more new Countrypage window will be opened in the MDI area (window title: "Country Page 1"). Now if we click the "New" button in "Country Page 1", one more new window will open in the MDI area (window title: "Country page 2") and so on - and I want to close the windows one by one by pressing the corresponding "Close" button in Countrypage. New window are opened only by pressing a "New" button.
And if we close the last opened window by pressing the "Close" button, the text item in the "Country" text-box will be automatically updated in the previous window's "Country" text-box and so on.
Main Script :
import sys,os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from sample_countrypage import Countrypage
class MainPage(QMainWindow):
count = 0
def __init__(self):
super().__init__()
self.mdi = QMdiArea()
self.mdi.setFixedSize(1000,400)
self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.setWindowTitle(" Sample Programme")
self.setGeometry(100,100,1600,600)
self.Ui()
self.show()
def Ui(self):
self.btn1=QPushButton("Country")
self.btn1.setFixedSize(100, 30)
self.btn1.clicked.connect(self.countrypage)
self.left_layout = QVBoxLayout()
self.right_layout = QHBoxLayout()
self.main_layout = QHBoxLayout()
self.left_layout.setContentsMargins(3,5,5,3)
self.left_layout.addWidget(self.btn1)
self.left_layout.addStretch()
self.right_layout.addWidget(self.mdi)
self.main_layout.setSpacing(5)
self.main_layout.setContentsMargins(0,0,0,0)
self.main_layout.addLayout(self.left_layout)
self.main_layout.addLayout(self.right_layout)
self.main_layout.addStretch()
widget = QWidget()
widget.setLayout(self.main_layout)
self.setCentralWidget(widget)
self.subwindow1 = QMdiSubWindow()
self.subwindow1.setObjectName("SubWindow_1")
# self.subwindow1.setWindowFlag(Qt.FramelessWindowHint)
print(Countrypage.btn2click)
def countrypage(self):
self.countrywindow = Countrypage()
self.subwindow1.setWidget(self.countrywindow)
self.subwindow1.setWindowTitle("Create Country")
self.subwindow1.setFixedWidth(300)
self.mdi.addSubWindow(self.subwindow1)
self.subwindow1.show()
self.mdi.cascadeSubWindows()
self.countrywindow.closeRequsted.connect(self.subwindow1close)
def subwindow1close(self):
print("close activated from mdi programme")
self.subwindow1.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
mainwindow = MainPage()
app.setStyle("Windows")
mainwindow.show()
sys.exit(app.exec_())
Countrypage.py
import sys,os
from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLineEdit,QFormLayout,QVBoxLayout,QHBoxLayout
from PyQt5.QtCore import pyqtSignal
class Countrypage(QWidget):
closeRequsted = pyqtSignal()
def __init__(self):
super().__init__()
self.btn1 = QPushButton("close")
self.btn2 = QPushButton("New")
self.btn1.clicked.connect(self.result)
self.btn2.clicked.connect(self.btn2click)
self.tb_country = QLineEdit()
self.tb_continent =QLineEdit()
self.form_layout = QFormLayout()
self.form_layout.addRow("Country",self.tb_country)
self.form_layout.addRow("continent",self.tb_continent)
self.form_layout.addRow("",self.btn2)
self.form_layout.addRow("",self.btn1)
self.setLayout(self.form_layout)
def result(self):
self.closeRequsted.emit()
def btn2click(self):
btn2text = (self.btn2.text())
print(btn2text)
if __name__=="__main__":
app = QApplication(sys.argv)
countrywin = Countrypage()
countrywin.show()
sys.exit(app.exec_())
The adding and closing of sub-windows is best handled by the main-window. The CountryPage class doesn't need to know anything about the sub-windows. The new/close buttons can be directly connected to methods of the main-window. This makes it easier to manage the sub-windows via the functions of the mdi-area.
Below is a re-write of your example which should do what you asked for:
Main Script:
import sys, os
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class MainPage(QMainWindow):
def __init__(self):
super().__init__()
self.mdi = QMdiArea()
self.mdi.setFixedSize(1000, 400)
self.mdi.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.mdi.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.setWindowTitle("Sample Programme")
self.setGeometry(100, 100, 1600, 600)
self.Ui()
def Ui(self):
self.btn1 = QPushButton("Country")
self.btn1.setFixedSize(100, 30)
self.btn1.clicked.connect(self.countrypage)
self.left_layout = QVBoxLayout()
self.right_layout = QHBoxLayout()
self.main_layout = QHBoxLayout()
self.left_layout.setContentsMargins(3, 5, 5, 3)
self.left_layout.addWidget(self.btn1)
self.left_layout.addStretch()
self.right_layout.addWidget(self.mdi)
self.main_layout.setSpacing(5)
self.main_layout.setContentsMargins(0, 0, 0, 0)
self.main_layout.addLayout(self.left_layout)
self.main_layout.addLayout(self.right_layout)
self.main_layout.addStretch()
widget = QWidget()
widget.setLayout(self.main_layout)
self.setCentralWidget(widget)
def countrypage(self):
page = Countrypage()
subwindow = self.mdi.addSubWindow(page)
subwindow.setWindowTitle("Create Country")
subwindow.setFixedWidth(300)
page.btn_close.clicked.connect(self.subwindowclose)
page.btn_new.clicked.connect(self.countrypage)
subwindow.show()
self.mdi.cascadeSubWindows()
def subwindowclose(self):
print("close activated from mdi programme")
current = self.mdi.activeSubWindow()
if current is not None:
self.mdi.activatePreviousSubWindow()
previous = self.mdi.activeSubWindow()
if previous is not None:
previous.widget().update_fields(current.widget())
current.close()
if __name__ == "__main__":
app = QApplication(sys.argv)
mainwindow = MainPage()
app.setStyle("Windows")
mainwindow.show()
sys.exit(app.exec_())
Countrypage.py:
import sys,os
from PyQt5.QtWidgets import QWidget,QApplication,QPushButton,QLineEdit,QFormLayout,QVBoxLayout,QHBoxLayout
from PyQt5.QtCore import pyqtSignal
class Countrypage(QWidget):
def __init__(self):
super().__init__()
self.btn_close = QPushButton("Close")
self.btn_new = QPushButton("New")
self.tb_country = QLineEdit()
self.tb_continent = QLineEdit()
self.form_layout = QFormLayout()
self.form_layout.addRow("Country", self.tb_country)
self.form_layout.addRow("Continent", self.tb_continent)
self.form_layout.addRow("", self.btn_close)
self.form_layout.addRow("", self.btn_new)
self.setLayout(self.form_layout)
def update_fields(self, other):
if isinstance(other, Countrypage):
self.tb_country.setText(other.tb_country.text())
self.tb_continent.setText(other.tb_continent.text())
else:
raise TypeError('invalid page type')

How can I generate the buttons and connect them to different functions? [duplicate]

This question already has answers here:
How do I assert the identity of a PyQt5 signal?
(2 answers)
Closed 2 years ago.
I've created a search engine in PyQt5, using the code below:
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super(Label, self).__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def show(self):
for labels in [self, self.lbl]:
labels.setVisible(True)
def hide(self):
for labels in [self, self.lbl]:
labels.setVisible(False)
def printsignal(self):
print("clicked")
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
The problem I have is, all the buttons share the same function and I don't know how to make them have different signals, as they are generated automatically. Basically, if I run the code it will show up like
this:
and when I press any of the buttons, it will print "clicked" (as in printsignal function). What I want is a different function for each button. Is there a way to do that?
Normally you can use self.sender().text() to get text from QButton which generated signal.
But because you create own widget Label with QButton and QLabel and you want text from label so you can get directly self.name
def printsignal(self):
print("clicked", self.name)
eventually self.lbl.text()
def printsignal(self):
print("clicked", self.lbl.text())
Working code.
I removed show(), hide() because you don't need it
import sys
from PyQt5.QtWidgets import (
QWidget, QLineEdit, QLabel, QScrollArea, QMainWindow,
QApplication, QHBoxLayout, QVBoxLayout, QSpacerItem, QSizePolicy, QCompleter, QPushButton
)
from PyQt5 import QtCore
from PyQt5.QtCore import Qt
tlist = ['thing1', 'thing2', 'thing3', 'thing4']
class Label(QWidget):
def __init__(self, name):
super().__init__()
self.name = name
self.lbl = QLabel(self.name)
self.lbl.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
self.btn = QPushButton("Preview")
self.btn.setMaximumSize(QtCore.QSize(100,100))
self.btn.clicked.connect(self.printsignal)
self.hbox = QHBoxLayout()
self.hbox.addWidget(self.lbl)
self.hbox.addWidget(self.btn)
self.setLayout(self.hbox)
def printsignal(self):
print("clicked", self.name)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__()
self.controls = QWidget()
self.controlsLayout = QVBoxLayout()
self.widgets = []
for name in tlist:
item = Label(name)
self.controlsLayout.addWidget(item)
self.widgets.append(item)
spacer = QSpacerItem(1, 1, QSizePolicy.Minimum, QSizePolicy.Expanding)
self.controlsLayout.addItem(spacer)
self.controls.setLayout(self.controlsLayout)
self.scroll = QScrollArea()
self.scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.scroll.setWidgetResizable(True)
self.scroll.setWidget(self.controls)
self.searchbar = QLineEdit()
self.searchbar.textChanged.connect(self.update_display)
self.completer = QCompleter(tlist)
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
self.searchbar.setCompleter(self.completer)
container = QWidget()
containerLayout = QVBoxLayout()
containerLayout.addWidget(self.searchbar)
containerLayout.addWidget(self.scroll)
container.setLayout(containerLayout)
self.setCentralWidget(container)
self.setGeometry(600, 100, 800, 600)
self.setWindowTitle('Search Engine')
def update_display(self, text):
for widget in self.widgets:
if text.lower() in widget.name.lower():
widget.show()
else:
widget.hide()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Can a checkable Qstandard item be centered within a QStandardItemModel column?

I have a table class with a column of check boxes. I'd like to center these within the column but using item.setTextAlignment(Qt.AlignCenter) doesn't work.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import (QDate, QDateTime, QRegExp, QSortFilterProxyModel, Qt,
QTime, QModelIndex, QSize, pyqtSignal, QObject)
from PyQt5.QtGui import QStandardItemModel, QIcon, QStandardItem
class Table(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.initUI()
self.show()
def initUI(self):
mainLayout = QVBoxLayout()
self.proxyModel = QSortFilterProxyModel()
self.proxyModel.setDynamicSortFilter(True)
self.sourceModel = QStandardItemModel(0, 2, self)
self.sourceModel.setHeaderData(0, Qt.Horizontal, '')
self.sourceModel.setHeaderData(1, Qt.Horizontal, 'Value')
self.proxyModel.setSourceModel(self.sourceModel)
self.proxyGroupBox = QGroupBox('data')
self.proxyView = QTreeView()
self.proxyView.setRootIsDecorated(False)
self.proxyView.setAlternatingRowColors(True)
self.proxyView.setModel(self.proxyModel)
self.proxyView.setEditTriggers(QAbstractItemView.NoEditTriggers)
proxyLayout = QGridLayout()
proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3)
self.proxyGroupBox.setLayout(proxyLayout)
mainLayout.addWidget(self.proxyGroupBox)
self.setLayout(mainLayout)
for i in range(5):
self.proxyView.resizeColumnToContents(0)
item = QStandardItem(True)
item.setCheckable(True)
item.setCheckState(False)
#item.setTextAlignment(Qt.AlignCenter)
self.sourceModel.setItem(i, 0, item)
self.sourceModel.setData(self.sourceModel.index(i, 1), i+1)
def setSourceModel(self, model):
self.proxyModel.setSourceModel(model)
if __name__=='__main__':
import sys
app = QApplication(sys.argv)
window = Table()
sys.exit(app.exec_())
Is there anyway to center each item of the first column?
If you want to change the alignment of the checkbox then you must use a QProxyStyle:
class CheckBoxProxyStyle(QProxyStyle):
def subElementRect(self, element, option, widget):
rect = super().subElementRect(element, option, widget)
if element == QStyle.SE_ItemViewItemCheckIndicator:
rect.moveCenter(option.rect.center())
return rect
self.proxyView = QTreeView()
self.proxyView.setStyle(CheckBoxProxyStyle(self.proxyView.style()))

How to stick widgets side by side

The code below creates a dialog window with three widgets: QLabel, QComboBox and QButton.
I want QLabel and QComboBox to be sitting on a same line. That is why both of these widgets are assigned to the same horizontal layout.
Resizing the dialog creates a huge empty space between the Label and ComboBox. How to assure that the left side of the Combo sticks to the right side of Label when dialog is resizing?
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication([])
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QVBoxLayout())
h_layout = QHBoxLayout()
self.layout().addLayout(h_layout)
label = QLabel(self)
label.setText('Month:')
combo = QComboBox(self)
h_layout.addWidget(label)
h_layout.addWidget(combo)
button = QPushButton('Ok')
self.layout().addWidget(button)
self.resize(200, 50)
self.show()
dialog = Dialog()
app.exec_()
You have to establish the size policy through QSizePolicy, in your case you must set the policy QSizePolicy::Expanding in the horizontal component of the QComboBox:
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication(sys.argv)
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QVBoxLayout())
h_layout = QHBoxLayout()
self.layout().addLayout(h_layout)
label = QLabel(self)
label.setText('Month:')
combo = QComboBox(self)
policy = combo.sizePolicy()
policy.setHorizontalPolicy(QSizePolicy.Expanding)
combo.setSizePolicy(policy)
h_layout.addWidget(label)
h_layout.addWidget(combo)
button = QPushButton('Ok')
self.layout().addWidget(button)
self.resize(200, 50)
self.show()
dialog = Dialog()
sys.exit(app.exec_())
Shorter and better solution is add parameter stretch=1 to addWidget() function:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
app = QApplication([])
class Dialog(QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QVBoxLayout())
h_layout = QHBoxLayout()
self.layout().addLayout(h_layout)
label = QLabel(self)
label.setText('Month:')
combo = QComboBox(self)
h_layout.addWidget(label)
h_layout.addWidget(combo, stretch=1)
button = QPushButton('Ok')
self.layout().addWidget(button)
self.resize(200, 50)
self.show()
dialog = Dialog()
app.exec_()

Delete space between Combobox and label (QGridlayout)

I'm trying to create a Application form by PySide, and i follow some tutorial , but i have a problem that is a space between QLabel and QCombobox.
This is my code
import sys
from PySide import QtCore, QtGui
from PySide.QtGui import *
from PySide.QtCore import *
class Window(QtGui.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setMinimumHeight(660)
self.setMinimumWidth(700)
self.setMaximumHeight(660)
self.setMaximumWidth(900)
grid = QtGui.QGridLayout()
grid.addWidget(self.First(), 0,0,2,0)
self.setLayout(grid)
self.setWindowTitle("Library")
self.resize(700, 660)
def First(self):
groupBox = QtGui.QFrame()
groupBox.setMaximumWidth(230)
groupBox.setMaximumHeight(700)
lbFile = QtGui.QLabel("File :",self)
lbFolders = QtGui.QLabel("Folders :",self)
cbFile = QtGui.QComboBox(self)
cbFile.addItem("File 1")
cbFile.addItem("File 2")
lvFolders = QtGui.QListView(self)
lvFolders.setMaximumWidth(220)
lvFolders.setMaximumHeight(500)
vbox = QtGui.QGridLayout()
vbox.addWidget(lbFile,0,0)
vbox.addWidget(cbFile,0,1)
vbox.addWidget(lbFolders,2,0)
vbox.addWidget(lvFolders,3,0,1,2)
groupBox.setLayout(vbox)
return groupBox
app = QApplication.instance()
if app is None:
app = QApplication(sys.argv)
clock = Window()
clock.show()
app.exec_()
and this is my Form :
I dont know how to delete the space between QLabel "File" and QCombobox "File 1"
Adjust the stretch factor for the second column of the layout, and possibly also make the folders label span both columns:
vbox = QtGui.QGridLayout()
vbox.addWidget(lbFile,0,0)
vbox.addWidget(cbFile,0,1)
vbox.addWidget(lbFolders,2,0,1,2)
vbox.addWidget(lvFolders,3,0,1,2)
vbox.setColumnStretch(1, 1)

Categories