QTreeView control left click vs right click - python

In my QTreeView when a user clicks an item in the list, i popup a dialog beneath the clicked treeview item. However, I only want this to happen when the user Left clicks. Currently this popup is displayed when the user both right-clicks and left clicks.
I want the context menu to show, like it does now, when the user right-clicks. And the popup dialog to show when only when the user left clicks an item. The right-click should still act as normal, selecting and item.
How do i fix this? The error occurs when i right-click over the furthest right column.
import os, sys, pprint
from Qt import QtGui, QtWidgets, QtCore
class Window(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.resize(800, 400)
self.uiSearch = QtWidgets.QLineEdit()
self.uiItems = QtWidgets.QTreeView()
self.uiItems.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
self.uiItems.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.uiItems.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.uiItems.setModel(QtGui.QStandardItemModel())
self.uiItems.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.uiSearch)
self.layout.addWidget(self.uiItems)
self.setLayout(self.layout)
for i in range(10):
col1 = QtGui.QStandardItem('Item' + str(i))
col2 = QtGui.QStandardItem('Item' + str(i))
col3 = QtGui.QStandardItem('Item' + str(i))
self.uiItems.model().appendRow([col1,col2,col3])
self.uiItems.clicked.connect(self.clickedItem)
self.uiItems.customContextMenuRequested.connect(self.openContextMenu)
self.myMenu = QtWidgets.QMenu('Menu', self)
self.myMenu.addAction(QtWidgets.QAction('Test',self))
def clickedItem(self, index):
if index.isValid():
rect = self.uiItems.visualRect(index)
pos = self.uiItems.viewport().mapToGlobal(rect.bottomLeft())
# create editor
dlg = QtWidgets.QDialog(self)
dlg.setWindowFlags(QtCore.Qt.Popup)
dlg.resize(rect.width(), 100)
dlg.move(pos)
dlg.show()
def openContextMenu(self):
self.myMenu.exec_(QtGui.QCursor.pos())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = Window()
ex.show()
app.exec_()

Related

PyQt5 Tab Widget: How can I get the index of active tab window on mouse click?

I have a Tab Widget with 2 Tabs. How can I get the index number of a Tab when I click on it?
self.tab = QTabWidget()
self.tab.addTab(self.widget1, "Tab1")
self.tab.addTab(self.widget2, "Tab2")
data_entry_tab.tabBarClicked.connect(self.OnTabClicked)
def OnTabClicked(self):
tab_bar = self.sender()
# I want to use idx to do some calculation
idx = ?
You can use the tabBarClicked signal:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.tabwidget = QtWidgets.QTabWidget()
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab1")
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab2")
self.tabwidget.addTab(QtWidgets.QWidget(), "Tab3")
self.setCentralWidget(self.tabwidget)
self.tabwidget.tabBarClicked.connect(self.handle_tabbar_clicked)
def handle_tabbar_clicked(self, index):
print(index)
print("x2:", index * 2)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
whatever you have your Qtabwidget set up as, like lets say. tabs = QTabWidget(), for instance. then you would use tabs.currentIndex() to find the index of the tab that is currently open. so then you can be like current_index = tabs.currentIndex(), and use the index for whatever it is you were needing it for.

Move widget pyqt in layout

Hi i have buttons in my code i would like when the user press insert new button it will move all the other button one row below and create a new button just under the one it was pressed this is my code
bascily i am trying to move all the button in layout one row below and after i add the new button :
def Insert_Stage(self) :
button = self.sender()
idx = self.Layout.indexOf(button)
location = self.Layout.getItemPosition(idx)
x=location[0]
z=self.Layout.rowCount()
print(x,z)
while(z >x+1):
items= self.Layout.itemAt(z)
# setting the item as widget
widget=items.widget()
index= self.Layout.indexOf(widget)
loc=self.Layout.getItemPosition(index)
d=loc[0]
y=loc[1]
if y!=0:
#widget.move(d+100,d)
self.Layout.addWidget(widget,(d+1),1)
else:
self.Layout.addWidget(widget,d+1,0)
z-=1
stage=QtGui.QPushButton(self)
stage.setObjectName(button.objectName())
k=(int(button.objectName()[5:])+1)
stage.setText('stage%d'%k)
self.Layout.addWidget(stage,(location[0]+1),0)
Assuming you are using a QVBoxLayout you have to use the insertWidget() method:
from PyQt4 import QtCore, QtGui
class Widget(QtGui.QLineEdit):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
lay = QtGui.QVBoxLayout(self)
for i in range(5):
btn = QtGui.QPushButton(
'button {}'.format(i),
clicked=self.on_clicked
)
lay.addWidget(btn)
#QtCore.pyqtSlot()
def on_clicked(self):
btn = self.sender()
ix = self.layout().indexOf(btn)
new_btn = QtGui.QPushButton(
"button {}".format(self.layout().count()),
clicked=self.on_clicked
)
self.layout().insertWidget(ix+1, new_btn)
if __name__ == '__main__':
import sys
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())

widgets placement in tabs

So I have this code:
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QWidget, QAction, QTabWidget, QVBoxLayout, QHBoxLayout, QComboBox, QLabel
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
from lang import getLang
import sys, os, configparser
config = configparser.ConfigParser()
config.read("Settings.ini")
# Config get setting and change setting
#print(config.get("Main", "language"))
#config.set("Main", "language", "danish")
#with open("Settings.ini", "w") as cfg_file:
#config.write(cfg_file)
class App(QMainWindow):
def __init__(self):
super().__init__()
# Window Settings
self.x, self.y, self.w, self.h = 0, 0, 300, 200
self.setGeometry(self.x, self.y, self.w, self.h)
self.window = MainWindow(self)
self.setCentralWidget(self.window)
self.setWindowTitle("Window title") # Window Title
self.show()
class MainWindow(QWidget):
def __init__(self, parent):
super(QWidget, self).__init__(parent)
layout = QVBoxLayout(self)
# Run this after settings
self.lang = getLang(config.get("Main", "language"))
# Initialize tabs
tab_holder = QTabWidget() # Create tab holder
tab_1 = QWidget() # Tab one
tab_2 = QWidget() # Tab two
# Add tabs
tab_holder.addTab(tab_1, self.lang["tab_1_title"]) # Add "tab1" to the tabs holder "tabs"
tab_holder.addTab(tab_2, self.lang["tab_2_title"]) # Add "tab2" to the tabs holder "tabs"
# Create first tab
tab_1.layout = QVBoxLayout(self)
tab_2.layout = QVBoxLayout(self)
# Buttons
button_start = QPushButton(self.lang["btn_start"])
button_stop = QPushButton(self.lang["btn_stop"])
button_test = QPushButton(self.lang["btn_test"])
# Button Extra
button_start.setToolTip("This is a tooltip for the button!") # Message to show when mouse hover
button_start.clicked.connect(self.on_click)
button_stop.clicked.connect(self.on_click)
button_test.clicked.connect(self.on_click)
#button_start.setEnabled(False)
# comboBox
label_language = QLabel("Language")
combo_language = QComboBox(self)
combo_language.addItem(self.lang["language_danish"])
combo_language.addItem(self.lang["language_english"])
# Move widgets
combo_language.move(50, 150)
label_language.move(50, 50)
# Tab Binding
self.AddToTab(tab_1, button_start)
self.AddToTab(tab_1, button_stop)
self.AddToTab(tab_2, label_language)
self.AddToTab(tab_2, combo_language)
# Add tabs to widget
tab_1.setLayout(tab_1.layout)
tab_2.setLayout(tab_2.layout)
layout.addWidget(tab_holder)
self.setLayout(layout)
#pyqtSlot()
def on_click(self):
button = self.sender().text()
if button == self.lang["btn_start"]:
print("Dank")
elif button == self.lang["btn_stop"]:
print("Not dank")
def AddToTab(self, tab, obj):
tab.layout.addWidget(obj)
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Currently it creates a window that contains 2 buttons on tab one. A "Start" and "Stop" button with no actual function yet other than printing text.
On tab 2 I have a label saying "Language:" and a dropdown menu that contains "Danish" and "English".
The problem I have with this, is that it's placement is really really weird and annoying as shown here:
I'm not sure how to change the placement as I can't just use .move on the text label, buttons and dropdown menu since they are placed in tabs.
For example, on tab two I would like the label "Language:" to be right to the left of the dropdown menu.
The problem is caused because you are using QVBoxLayout to set the widgets inside each tab. The task of the layout is to manage the position and size of the widgets so you can not use move(), besides it is not necessary.
The solution is that you create a custom layout for each tab, but keeping an order will create a custom widget for each tab, in the case of the first tab I'll continue using QVBoxlayout but add a stretch so that the widget stays stuck in the top position. In the second case I will combine a QVBoxLayout with a QHBoxLayout, the QHBoxLayout will use it to place the QLabel and the QComboBox and the QVBoxLayout will use it to push the widgets to the top position.
Implementing the above, I have omitted the lang for obvious reasons, we get the following:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys, os, configparser
config = configparser.ConfigParser()
config.read("Settings.ini")
# Config get setting and change setting
#print(config.get("Main", "language"))
#config.set("Main", "language", "danish")
#with open("Settings.ini", "w") as cfg_file:
#config.write(cfg_file)
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
# Window Settings
self.x, self.y, self.w, self.h = 0, 0, 300, 200
self.setGeometry(self.x, self.y, self.w, self.h)
self.window = MainWindow(self)
self.setCentralWidget(self.window)
self.setWindowTitle("Window title") # Window Title
self.show()
class GeneralWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(GeneralWidget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
# Buttons
button_start = QtWidgets.QPushButton("start") #self.lang["btn_start"])
button_stop = QtWidgets.QPushButton("stop") #self.lang["btn_stop"])
# Button Extra
button_start.setToolTip("This is a tooltip for the button!") # Message to show when mouse hover
button_start.clicked.connect(self.on_click)
button_stop.clicked.connect(self.on_click)
lay.addWidget(button_start)
lay.addWidget(button_stop)
lay.addStretch()
#QtCore.pyqtSlot()
def on_click(self):
button = self.sender().text()
if button == self.lang["btn_start"]:
print("Dank")
elif button == self.lang["btn_stop"]:
print("Not dank")
class OptionsWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(OptionsWidget, self).__init__(parent)
lay = QtWidgets.QVBoxLayout(self)
hlay = QtWidgets.QHBoxLayout()
lay.addLayout(hlay)
lay.addStretch()
label_language = QtWidgets.QLabel("Language")
combo_language = QtWidgets.QComboBox(self)
combo_language.addItem("item1") #self.lang["language_danish"])
combo_language.addItem("item2") #self.lang["language_english"])
hlay.addWidget(label_language)
hlay.addWidget(combo_language)
class MainWindow(QtWidgets.QWidget):
def __init__(self, parent):
super(MainWindow, self).__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
# Run this after settings
# self.lang = getLang(config.get("Main", "language"))
# Initialize tabs
tab_holder = QtWidgets.QTabWidget() # Create tab holder
tab_1 = GeneralWidget() # Tab one
tab_2 = OptionsWidget() # Tab two
# Add tabs
tab_holder.addTab(tab_1, "General") #self.lang["tab_1_title"]) # Add "tab1" to the tabs holder "tabs"
tab_holder.addTab(tab_2, "Options") #self.lang["tab_2_title"]) # Add "tab2" to the tabs holder "tabs"
layout.addWidget(tab_holder)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())

What kind of signal is emitted when QScrollArea entry is selected/clicked?

I'm having though time figuring out what kind of signal is emitted in following situation:
Basicly that's QScrollArea that holds multiple QTableWidgets:
class ScrollArea(QtGui.QScrollArea):
def __init__(self):
super(ScrollArea, self).__init__()
self.scroll_widget = QtGui.QWidget()
self.scroll_layout = QtGui.QVBoxLayout()
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setWidgetResizable(True)
self.__create_content()
self.setWidget(self._content_widget)
self.scroll_layout.addWidget(self)
self.scroll_widget.setLayout(self.scroll_layout)
def __create_content(self):
self._content_widget = QtGui.QWidget()
self._content_widget_layout = QtGui.QVBoxLayout()
self._content_widget.setLayout(self._content_widget_layout)
def add_item(self, item):
self._content_widget_layout.addWidget(item)
I'm using Plastique style for QApplication. As it can be seen from the above picture, when an item is clicked inside QScrollArea, blue border appears. What I would like to know is which signal is emitted when the border is drawn? I need this information so I can append a row to the selected QTableWidget whenever a button (on the left side) is clicked.
Also you can see that there is a 'x' inside each table, when 'x' is pressed that QTableWidget gets removed from QScrollArea. If there is a solution for previous problem, I could also remove QTableWidget depending on user selection rather than user clicking the 'x'.
To get the widget that has the focus you can use the focusChanged signal of QApplication:
from PyQt4 import QtCore, QtGui
class HorizontalHeader(QtGui.QHeaderView):
def __init__(self, parent=None):
super(HorizontalHeader, self).__init__(QtCore.Qt.Horizontal, parent)
self.button = QtGui.QToolButton(self, text="x")
self.sectionResized.connect(self.handleSectionResized)
def handleSectionResized(self):
last_ix = self.count() - 1
pos = QtCore.QPoint(self.sectionViewportPosition(last_ix) + self.sectionSize(last_ix) , 0)
self.button.move(pos)
def showEvent(self, event):
self.handleSectionResized()
super(HorizontalHeader, self).showEvent(event)
class TableView(QtGui.QTableView):
def __init__(self, *args, **kwargs):
super(TableView, self).__init__(*args, **kwargs)
header = HorizontalHeader(self)
header.button.clicked.connect(self.deleteLater)
self.setHorizontalHeader(header)
QtGui.qApp.focusChanged.connect(self.onFocusChanged)
def onFocusChanged(self, old, new):
if new == self:
self.deleteLater()
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
scrollArea = QtGui.QScrollArea()
scrollArea.setWidgetResizable(True)
widget = QtGui.QWidget()
scrollArea.setWidget(widget)
lay = QtGui.QVBoxLayout(widget)
for i in range(10):
w = TableView()
model = QtGui.QStandardItemModel(4, 2, w)
w.setModel(model)
lay.addWidget(w)
scrollArea.show()
sys.exit(app.exec_())

PyQt5: Check the existance of dynamically created Checkboxes and Refer them

Basic Layout of the Code
Here, every time the user clicks on the PushButton 'Press me', a new CheckBox will be generated.
from PyQt5 import QtWidgets, QtGui, QtCore
count = 1
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.vlayout = QtWidgets.QVBoxLayout()
self.pushButton1 = QtWidgets.QPushButton("Press me", self)
self.pushButton1.clicked.connect(self.addCheckbox(count))
self.pushButton2 = QtWidgets.QPushButton("OK", self)
self.vlayout.addWidget(self.pushButton1)
self.vlayout.addWidget(self.pushButton2)
self.setLayout(self.vlayout)
def addCheckbox(self,count):
global count
self.vlayout.addWidget(str(count),QtWidgets.QCheckBox())
count = count +1
application = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Hello')
window.resize(250, 180)
window.show()
sys.exit(application.exec_())
What I wish to do?
Now you will have unique check boxes, each with a different number, I want to add further functionality.
Every time the user chooses specific checkboxes, I want to know which checkbox did the user click after he clicks the PushButton OK.
Eg: I click on checkbox 1 -> OK -> print 1 on the screen
How can I do this?
PS: We need to consider the possibility that the user never clicks Press me, so no ckeckboxes will be generated and straightaway clicks on OK
Just use a list to store the QCheckBox, and verify by iterating.
from PyQt5 import QtWidgets, QtGui, QtCore
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.vlayout = QtWidgets.QVBoxLayout(self)
self.pushButton1 = QtWidgets.QPushButton("Press me")
self.pushButton1.clicked.connect(self.addCheckbox)
self.pushButton2 = QtWidgets.QPushButton("OK")
self.pushButton2.clicked.connect(self.onClicked)
self.vlayout.addWidget(self.pushButton1)
self.vlayout.addWidget(self.pushButton2)
self.checkboxes = []
def addCheckbox(self):
checkbox = QtWidgets.QCheckBox()
self.checkboxes.append(checkbox)
self.vlayout.addWidget(checkbox)
def onClicked(self):
for i, checkbox in enumerate(self.checkboxes):
if checkbox.isChecked():
print("print {} on the screen".format(i))
if __name__ == '__main__':
import sys
application = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('Hello')
window.resize(250, 180)
window.show()
sys.exit(application.exec_())

Categories

Resources