How to switch widgets visibility by request - python

The code below creates a single dialog window with three rows of widgets:
a combo, lineEdit and dateEdit. When combobox shows 'Show LineEdit' I would like lineEdit to be visible and dateEdit to be hidden. When "Show DateEdit" is selected I would like to hide LineEdit and show DateEdit instead. How to achieve it?
from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
for i in range(3):
row = QtGui.QHBoxLayout()
combo = QtGui.QComboBox()
combo.addItems(['Show LineEdit','Show DateEdit'])
combo.activated.connect(self.activated)
row.addWidget(combo)
self.lineEdit = QtGui.QLineEdit()
self.dateEdit = QtGui.QDateEdit()
self.dateEdit.setVisible(False)
row.addWidget(self.lineEdit)
row.addWidget(self.dateEdit)
self.layout().insertLayout(i, row)
def activated(self):
print self.sender()
panel=Dialog()
panel.show()
app.exec_()

The strategy is to create a dictionary that has as a key a combobox and values ​​a dictionary of the corresponding other widget, then use the activated method that can return a text or a number.
from PyQt4 import QtGui
app = QtGui.QApplication([])
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
self.widgets = {}
for i in range(3):
row = QtGui.QHBoxLayout()
combo = QtGui.QComboBox()
combo.addItems(['Show LineEdit', 'Show DateEdit'])
combo.activated[str].connect(self.activated)
row.addWidget(combo)
lineEdit = QtGui.QLineEdit()
dateEdit = QtGui.QDateEdit()
self.widgets[combo] = [lineEdit, dateEdit]
self.changeWidget(combo.currentText(), lineEdit, dateEdit)
row.addWidget(lineEdit)
row.addWidget(dateEdit)
self.layout().insertLayout(i, row)
def activated(self, text):
linedit, dateEdit = self.widgets[self.sender()]
self.changeWidget(text, linedit, dateEdit)
def changeWidget(self, text, linedit, dateEdit):
if text == 'Show LineEdit':
linedit.setVisible(True)
dateEdit.setVisible(False)
elif text == 'Show DateEdit':
linedit.setVisible(False)
dateEdit.setVisible(True)
panel = Dialog()
panel.show()
app.exec_()

Inspired by eyllanesc answer posted above but with no dictionary.
from PyQt4 import QtGui
app = QtGui.QApplication([])
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setLayout(QtGui.QVBoxLayout())
for i in range(3):
row = QtGui.QHBoxLayout()
combo = QtGui.QComboBox()
combo.addItems(['Show LineEdit', 'Show DateEdit'])
combo.activated[str].connect(self.activated)
row.addWidget(combo)
combo.lineEdit = QtGui.QLineEdit()
combo.dateEdit = QtGui.QDateEdit()
row.addWidget(combo.lineEdit)
row.addWidget(combo.dateEdit)
self.layout().insertLayout(i, row)
def activated(self, title):
combo = self.sender()
if title == 'Show LineEdit':
combo.lineEdit.setVisible(True)
combo.dateEdit.setVisible(False)
else:
combo.lineEdit.setVisible(False)
combo.dateEdit.setVisible(True)
panel = Dialog()
panel.show()
app.exec_()

Related

How can i add push button to each and every item of the list view

Here is my sample code,i want to add a push button to each and every row of the list view.I am not found any method to set the widget to model.Can any one please help me how to add widget for each and every row of the list view.Thank you in advance.
Given below is my code:
import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class MyCustomWidget(QWidget):
def __init__(self,parent=None):
super(MyCustomWidget, self).__init__(parent)
self.row = QHBoxLayout()
self.row.addWidget(QPushButton("add"))
self.setLayout(self.row)
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent=parent)
vLayout = QtGui.QVBoxLayout(self)
hLayout = QtGui.QHBoxLayout()
self.lineEdit = QtGui.QLineEdit()
hLayout.addWidget(self.lineEdit)
self.filter = QtGui.QPushButton("filter", self)
hLayout.addWidget(self.filter)
self.list = QtGui.QListView(self)
vLayout.addLayout(hLayout)
vLayout.addWidget(self.list)
self.model = QtGui.QStandardItemModel(self.list)
codes = [
'windows',
'windows xp',
'windows7',
'hai',
'habit',
'hack',
'good'
]
self.list.setModel(self.model)
for code in codes:
item = QtGui.QStandardItem(code)
self.model.appendRow(item)
self.list.setIndexWidget(item.index(), QtGui.QPushButton("button"))
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
You have to create a custom widget where you must set the button on the right side with a layout.
import sys
from PyQt4 import QtCore, QtGui
class CustomWidget(QtGui.QWidget):
def __init__(self, parent=None):
super(CustomWidget, self).__init__(parent)
self.button = QtGui.QPushButton("button")
lay = QtGui.QHBoxLayout(self)
lay.addWidget(self.button, alignment=QtCore.Qt.AlignRight)
lay.setContentsMargins(0, 0, 0, 0)
class Dialog(QtGui.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent=parent)
vLayout = QtGui.QVBoxLayout(self)
hLayout = QtGui.QHBoxLayout()
self.lineEdit = QtGui.QLineEdit()
hLayout.addWidget(self.lineEdit)
self.filter = QtGui.QPushButton("filter", self)
hLayout.addWidget(self.filter)
self.list = QtGui.QListView(self)
vLayout.addLayout(hLayout)
vLayout.addWidget(self.list)
self.model = QtGui.QStandardItemModel(self.list)
codes = [
'windows',
'windows xp',
'windows7',
'hai',
'habit',
'hack',
'good'
]
self.list.setModel(self.model)
for code in codes:
item = QtGui.QStandardItem(code)
self.model.appendRow(item)
self.list.setIndexWidget(item.index(), CustomWidget())
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())

How to make a tab pane with no title bar?

I want to make GUI like below with PyQt5, but I can't find an example to help me.
I searched for "change layout on qwidget" and "tab pane with no title bar" and "card layout" without luck. How can I make this with PyQt5?
You have to use a QStackedLayout (or a QStackedWidget) that changes pages when the buttons are pressed. And the first page should have the buttons. I have also implemented the back() method that returns to the initial page, that slot must be invoked when the Change button is pressed:
from functools import partial
from PyQt5 import QtCore, QtWidgets
class CardWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(CardWidget, self).__init__(parent)
self._layout = QtWidgets.QStackedLayout(self)
button_widget = QtWidgets.QWidget()
self.btn_lay = QtWidgets.QFormLayout(button_widget)
self._layout.addWidget(button_widget)
def add_widget(self, text, widget):
self._layout.addWidget(widget)
btn = QtWidgets.QPushButton(text)
self.btn_lay.addRow(btn)
btn.clicked.connect(partial(self._layout.setCurrentWidget, widget))
#QtCore.pyqtSlot()
def back(self):
self._layout.setCurrentIndex(0)
class Widget(QtWidgets.QWidget):
backSignal = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.le1 = QtWidgets.QLineEdit()
self.le2 = QtWidgets.QLineEdit()
button = QtWidgets.QPushButton("Change")
button.clicked.connect(self.backSignal)
flay = QtWidgets.QFormLayout()
flay.addRow("Value 1:", self.le1)
flay.addRow("Value 2:", self.le2)
lay = QtWidgets.QVBoxLayout(self)
lay.addLayout(flay)
lay.addWidget(button)
def create_label():
label = QtWidgets.QLabel(
"Some Other Components",
alignment=QtCore.Qt.AlignCenter
)
label.setStyleSheet("background-color:blue;")
return label
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
c = CardWidget()
for i in range(3):
w = Widget()
w.backSignal.connect(c.back)
c.add_widget("Want to Change value {}".format(i+1), w)
p = QtWidgets.QWidget()
lay = QtWidgets.QGridLayout(p)
lay.addWidget(create_label(), 0, 0, 1, 2)
lay.addWidget(c, 1, 0)
lay.addWidget(create_label(), 1, 1)
lay.setColumnStretch(0, 1)
lay.setColumnStretch(1, 1)
lay.setRowStretch(0, 1)
lay.setRowStretch(1, 1)
p.resize(640, 480)
p.show()
sys.exit(app.exec_())

PyQt5 context menu for QTableWidget column head

is there a way to get a context menu on a tables column head.
Find nothing about that in PyQt5's tuts.
the table's context menu is simple but the column heads don't affect.
# dlg is a QDialog object
self.tbl = QtWidgets.QTableWidget(dlg)
self.tbl.setContextMenuPolicy( Qt.CustomContextMenu )
You have to use the QHeaderView of the QTableWidget:
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.tbl = QtWidgets.QTableWidget(10, 10, self)
for w in (self.tbl.horizontalHeader(), self.tbl.verticalHeader(), self.tbl):
w.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
w.customContextMenuRequested.connect(self.on_customContextMenuRequested)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.tbl)
#QtCore.pyqtSlot(QtCore.QPoint)
def on_customContextMenuRequested(self, pos):
widget = self.sender()
if isinstance(widget, QtWidgets.QAbstractItemView):
widget = widget.viewport()
menu = QtWidgets.QMenu()
menu.addAction("Foo Action")
menu.exec_(widget.mapToGlobal(pos))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())
Update:
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.tbl = QtWidgets.QTableWidget(10, 10, self)
self.tbl.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tbl.customContextMenuRequested.connect(self.on_customContextMenuRequested_tw)
self.tbl.verticalHeader().setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tbl.verticalHeader().customContextMenuRequested.connect(self.on_customContextMenuRequested_vh)
self.tbl.horizontalHeader().setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tbl.horizontalHeader().customContextMenuRequested.connect(self.on_customContextMenuRequested_hh)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.tbl)
#QtCore.pyqtSlot(QtCore.QPoint)
def on_customContextMenuRequested_tw(self, pos):
menu = QtWidgets.QMenu()
menu.addAction("Foo Action TW")
menu.exec_(self.tbl.viewport().mapToGlobal(pos))
#QtCore.pyqtSlot(QtCore.QPoint)
def on_customContextMenuRequested_vh(self, pos):
menu = QtWidgets.QMenu()
menu.addAction("Foo Action VH")
menu.exec_(self.tbl.verticalHeader().mapToGlobal(pos))
#QtCore.pyqtSlot(QtCore.QPoint)
def on_customContextMenuRequested_hh(self, pos):
menu = QtWidgets.QMenu()
menu.addAction("Foo Action HH")
menu.exec_(self.tbl.horizontalHeader().mapToGlobal(pos))
You need to set the context menu policy on the header itself (if I've understood correctly), so...
self.tbl = QtWidgets.QTableWidget(dlg)
self.tbl.horizontalHeader().setContextMenuPolicy(Qt.CustomContextMenu)
and connect to the `QHeaderView::customContextMenuRequested signal...
self.tbl.horizontalHeader().customContextMenuRequested.connect(self.handle_context_menu_request)

PyQt Options for each Tab Widget

I have a tab widget that contains table widgets for each tab, and I also have a dock widget with options. One of the options is the column count, and I want to change it as soon as the column count spin box value changes. But when switching to a different tab, I'd like the spin box value (and all other options) to reset / switch to that specific tab's settings.
My question is how to best do this and still have the options as a dock widget. I could store all settings as variables for each tab widget and then change the value each time a new tab is opened, I guess, but maybe there is a better solution.
from PyQt5 import QtWidgets, QtCore
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(MainWindow, self).__init__()
self.__setup__()
def __setup__(self):
self.resize(400, 400)
tabWidget = TabWidget(self)
self.setCentralWidget(tabWidget)
options = Options(self)
optionsDock = QtWidgets.QDockWidget()
optionsDock.setWidget(options)
optionsDock.setWindowTitle("Options")
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, optionsDock)
options.spinBox_columns.valueChanged.connect(lambda: tabWidget.tabWidget.currentWidget().
setColumnCount(options.spinBox_columns.value()))
class Options(QtWidgets.QWidget):
def __init__(self, parent):
super(Options, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.spinBox_columns = QtWidgets.QSpinBox()
self.spinBox_columns.setValue(1)
self.spinBox_columns.setMinimum(1)
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.spinBox_columns)
self.setLayout(layout)
class TabWidget(QtWidgets.QWidget):
def __init__(self, parent):
super(TabWidget, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.tabWidget = QtWidgets.QTabWidget()
for i in range(3):
widget = QtWidgets.QTableWidget()
widget.setColumnCount(1)
widget.setRowCount(3)
self.tabWidget.addTab(widget, "Column " + str(i))
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.tabWidget)
self.setLayout(layout)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
You have to connect the currentChanged signal provided by the index of the tab, then use the widget() method to obtain the index associated with that index, then access its QTabWidget and obtain the number of columns using it to place the value to the QSpinBox.
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.__setup__()
def __setup__(self):
self.resize(400, 400)
tabWidget = TabWidget(self)
self.setCentralWidget(tabWidget)
options = Options(self)
optionsDock = QtWidgets.QDockWidget()
optionsDock.setWidget(options)
optionsDock.setWindowTitle("Options")
self.addDockWidget(QtCore.Qt.TopDockWidgetArea, optionsDock)
tabWidget.tabWidget.currentChanged.connect(lambda index: options.spinBox_columns.
setValue(tabWidget.tabWidget.widget(index).columnCount()))
options.spinBox_columns.valueChanged.connect(lambda value: tabWidget.tabWidget.currentWidget().
setColumnCount(value))

PyQt: How to hide QMainWindow

Clicking Dialog_01's button hides its window and opens Dialog_02. Clicking Dialog_02's button should close its windows and unhide Dialog_01. How to achieve it?
import sys, os
from PyQt4 import QtCore, QtGui
class Dialog_02(QtGui.QMainWindow):
def __init__(self):
super(Dialog_02, self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
Button_02 = QtGui.QPushButton("Close THIS and Unhide Dialog 01")
Button_02.clicked.connect(self.closeAndReturn)
myBoxLayout.addWidget(Button_02)
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.setWindowTitle('Dialog 02')
def closeAndReturn(self):
self.close()
class Dialog_01(QtGui.QMainWindow):
def __init__(self):
super(Dialog_01, self).__init__()
myQWidget = QtGui.QWidget()
myBoxLayout = QtGui.QVBoxLayout()
Button_01 = QtGui.QPushButton("Hide THIS and Open Dialog 02")
Button_01.clicked.connect(self.callAnotherQMainWindow)
myBoxLayout.addWidget(Button_01)
myQWidget.setLayout(myBoxLayout)
self.setCentralWidget(myQWidget)
self.setWindowTitle('Dialog 01')
def callAnotherQMainWindow(self):
self.hide()
self.dialog_02 = Dialog_02()
self.dialog_02.show()
self.dialog_02.raise_()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
dialog_1 = Dialog_01()
dialog_1.show()
sys.exit(app.exec_())
Make the first window a parent of the second window:
class Dialog_02(QtGui.QMainWindow):
def __init__(self, parent):
super(Dialog_02, self).__init__(parent)
# ensure this window gets garbage-collected when closed
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
...
def closeAndReturn(self):
self.close()
self.parent().show()
class Dialog_01(QtGui.QMainWindow):
...
def callAnotherQMainWindow(self):
self.hide()
self.dialog_02 = Dialog_02(self)
self.dialog_02.show()
If you want the same dialog to be shown each time, do something like:
def callAnotherQMainWindow(self):
self.hide()
if not hassattr(self, 'dialog_02'):
self.dialog_02 = Dialog_02(self)
self.dialog_02.show()
and hide() the child window, rather than closing it.

Categories