I have contextmenu to a listWidget with delete and rename item. For delete, I used RemoveRow. But, I can't rename with user-input. How can I replace this line item.setText('new_name') by an action allow my change name by user
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItems('apple orange lemon'.split())
self.listWidget.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.listWidget)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.listWidget):
menu = QtWidgets.QMenu()
Delete = menu.addAction('Delete')
Rename = menu.addAction('Rename')
#action = menu.exec_(event.globalPos())
action = menu.exec_(self.mapToGlobal(event.pos())) #when inside self
if action == Delete:
item = source.itemAt(event.pos())
source.model().removeRow(source.currentRow())
elif action == Rename:
item = source.itemAt(event.pos())
#
item.setText('new')
"How can I rename by user input, not by setText??"
return True
return super(Dialog, self).eventFilter(source, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
You can use QInputDialog.getText() to ask for new text and use it with setText().
elif action == Rename:
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:")
if okPressed and text != '':
item = source.itemAt(event.pos())
item.setText(text)
You can even copy text from list to QInputDialog so user can edit it.
elif action == Rename:
item = source.itemAt(event.pos())
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:", text=item.text())
if okPressed and text != '':
item.setText(text)
Full working code
import sys
from PyQt5 import QtCore, QtWidgets
class Dialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(Dialog, self).__init__()
self.listWidget = QtWidgets.QListWidget()
self.listWidget.addItems('apple orange lemon'.split())
self.listWidget.installEventFilter(self)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.listWidget)
def eventFilter(self, source, event):
if (event.type() == QtCore.QEvent.ContextMenu and
source is self.listWidget):
menu = QtWidgets.QMenu()
Delete = menu.addAction('Delete')
Rename = menu.addAction('Rename')
#action = menu.exec_(event.globalPos())
action = menu.exec_(self.mapToGlobal(event.pos())) #when inside self
if action == Delete:
item = source.itemAt(event.pos())
source.model().removeRow(source.currentRow())
elif action == Rename:
item = source.itemAt(event.pos())
text, okPressed = QtWidgets.QInputDialog.getText(self, "New name","New name:", text=item.text())
if okPressed and text != '':
item.setText(text)
return True
return super(Dialog, self).eventFilter(source, event)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Dialog()
window.setGeometry(600, 100, 300, 200)
window.show()
sys.exit(app.exec_())
Related
I was inspired by this repo to add custom tooltip text to items when they are added to the QListWidget. However, I only want the tooltip message to appear when the item is chosen. How would I implement this?
Here is a GUI example that I have to test this feature:
import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time
class GUI(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.__init_ui()
def closeEvent(self, event):
super().closeEvent(event)
def __init_ui(self):
self.setWindowTitle('QListWidgetToolTipDemo')
self.history_log = HistoryList()
self.history_log.itemDoubleClicked.connect(self.history_item_selected)
self.history_log.returnPressed.connect(self.history_item_selected)
self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.line_edit = QtWidgets.QLineEdit()
self.line_edit.returnPressed.connect(self.populate_history)
self.middle_layout = QtWidgets.QHBoxLayout()
self.middle_layout.addWidget(self.history_log)
self.middle_layout.addWidget(self.line_edit)
middle_layout_wrapper = QtWidgets.QWidget()
middle_layout_wrapper.setLayout(self.middle_layout)
middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# Sets full GUI layout
gui_layout = QtWidgets.QVBoxLayout()
gui_layout.addWidget(middle_layout_wrapper)
gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.setLayout(gui_layout)
def populate_history(self):
self.history_log.addItem(self.line_edit.text())
self.line_edit.clear()
def history_item_selected(self):
self.line_edit.setText(self.history_log.currentItem().text())
class HistoryList(QtWidgets.QListWidget):
returnPressed = QtCore.pyqtSignal()
def __init__(self) -> None:
super().__init__()
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.setMouseTracking(True)
self.itemEntered.connect(self.__showToolTip)
def keyPressEvent(self, ev):
super().keyPressEvent(ev)
if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
def addItem(self, aitem) -> None:
item = ''
text = ''
if isinstance(aitem, str):
item = QtWidgets.QListWidgetItem()
text = aitem
item.setText(text)
elif isinstance(aitem, QtWidgets.QListWidgetItem):
item = aitem
text = item.text()
self.setItemWidget(item, QtWidgets.QWidget())
super().addItem(item)
def __showToolTip(self, item: QtWidgets.QListWidgetItem):
text = item.text()
text_width = self.fontMetrics().boundingRect(text).width()
width = self.width()
info = {"time":str(time.time()), "entry":text}
info = json.dumps(info, indent=4)
item.setToolTip(info)
if __name__ == "__main__":
app = QtWidgets.QApplication([])
console = GUI()
screensize = app.desktop().availableGeometry().size()
console.show()
exit(app.exec_())
Currently, the following is how a tooltip works for any item:
Example where only display tooltip when item is selected:
Expanding on the suggestion from musicamante in the comments, I was able to get tooltip to display only for the selected item by overriding the event method and watch for a tooltip event (inspired from this SO post)
import serial, time, sys
import serial.tools.list_ports
from PyQt5 import QtGui, QtWidgets, QtCore
import json, time
class GUI(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.__init_ui()
def closeEvent(self, event):
super().closeEvent(event)
def __init_ui(self):
self.setWindowTitle('QListWidgetToolTipDemo')
self.history_log = HistoryList()
self.history_log.itemDoubleClicked.connect(self.history_item_selected)
self.history_log.returnPressed.connect(self.history_item_selected)
self.history_log.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
self.line_edit = QtWidgets.QLineEdit()
self.line_edit.returnPressed.connect(self.populate_history)
self.middle_layout = QtWidgets.QHBoxLayout()
self.middle_layout.addWidget(self.history_log)
self.middle_layout.addWidget(self.line_edit)
middle_layout_wrapper = QtWidgets.QWidget()
middle_layout_wrapper.setLayout(self.middle_layout)
middle_layout_wrapper.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
# Sets full GUI layout
gui_layout = QtWidgets.QVBoxLayout()
gui_layout.addWidget(middle_layout_wrapper)
gui_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
gui_layout.setContentsMargins(QtCore.QMargins(0, 0, 0, 0))
self.setLayout(gui_layout)
def populate_history(self):
self.history_log.addItem(self.line_edit.text())
self.line_edit.clear()
def history_item_selected(self):
self.line_edit.setText(self.history_log.currentItem().text())
class HistoryList(QtWidgets.QListWidget):
returnPressed = QtCore.pyqtSignal()
def __init__(self) -> None:
super().__init__()
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
self.setMouseTracking(True)
self.itemEntered.connect(self.__addToolTip)
self.items_tooltip_info_dict = dict()
def keyPressEvent(self, ev):
super().keyPressEvent(ev)
if ev.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
self.returnPressed.emit()
def event(self, e: QtCore.QEvent) -> bool:
if e.type() == QtCore.QEvent.ToolTip:
if not self.selectedItems():
QtWidgets.QToolTip.hideText()
return True
else:
index = self.indexFromItem(self.currentItem()).row()
info = json.dumps(self.items_tooltip_info_dict[index], indent=4)
QtWidgets.QToolTip.showText(e.globalPos(),info)
e.accept()
return super().event(e)
def addItem(self, aitem) -> None:
item = ''
text = ''
if isinstance(aitem, str):
item = QtWidgets.QListWidgetItem()
text = aitem
item.setText(text)
elif isinstance(aitem, QtWidgets.QListWidgetItem):
item = aitem
text = item.text()
self.setItemWidget(item, QtWidgets.QWidget())
super().addItem(item)
def __addToolTip(self, item: QtWidgets.QListWidgetItem):
text = item.text()
info = {"time":str(time.time()), "entry":text}
index = self.indexFromItem(item).row()
self.items_tooltip_info_dict[index] = info
if __name__ == "__main__":
app = QtWidgets.QApplication([])
console = GUI()
screensize = app.desktop().availableGeometry().size()
console.show()
exit(app.exec_())
Summary:
I've been using QMessageBox in my application (for this purpose asking for saving project before closing, Error messages), And now I want to have a custom style (Custom title bar, custom buttons and so on), I found it is hard to do that with QMessageBox, And since I've been using a QDialog in my application as well (For this purpose: Taking input from user), I decided to use a custom QDialog (Make my own style on it) instead of QMessageBox for these all previous purpose, since it is easier to customize and creating my style.
The problem:
The problem that I have now is: QDialog return only a flag value (0,1) depending on the button role And that's fine if I have only 2 buttons BUT here I have 3 (Save, Cancel, Close), Save will return 1 and both Close and Cancel return 0. And QMessageBox as I've seen it return the id of the Button that was clicked.
An example (commented well hopefully :D):
from PyQt5.QtWidgets import *
class CustomDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Data will be lost")
label = QLabel("Are you sure you want close the app before saving?")
buttonBox = QDialogButtonBox()
buttonBox.addButton(QDialogButtonBox.Save)
buttonBox.addButton(QDialogButtonBox.Cancel)
buttonBox.addButton(QDialogButtonBox.Close)
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(buttonBox)
self.resize(300, 100)
self.setLayout(layout)
# These two lines, return 0 or 1.
buttonBox.rejected.connect(self.reject)
buttonBox.accepted.connect(self.accept)
class Window(QWidget):
def __init__(self):
super().__init__()
label = QLabel('Hello Dialog', self)
open_dialog_button = QPushButton('Open Dialog', self)
open_dialog_button.clicked.connect(self.showDialog)
open_message_box_button = QPushButton('Open Message Box', self)
open_message_box_button.clicked.connect(self.show_message_box)
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(open_dialog_button)
layout.addWidget(open_message_box_button)
self.setLayout(layout)
def showDialog(self):
self.dialog = CustomDialog(self)
btn_clicked = self.dialog.exec_() # dialog exec returns 0 or 1 (Save = 1, Close and Cancel returns 0)
# I want something like this.
if btn_clicked == QDialogButtonBox.Save:
print("Close.. After Saving...")
elif btn_clicked == QDialogButtonBox.Close:
print("Close.. Without saving")
else:
print("Cancel.. Don't exit the program")
def show_message_box(self):
msg = QMessageBox()
msg.setIcon(QMessageBox.Warning)
msg.setText("Are you sure you want close the app before saving?")
msg.setStandardButtons(QMessageBox.Close | QMessageBox.Save | QMessageBox.Cancel)
msg.setWindowTitle("Data will be lost")
btn_clicked = msg.exec_()
# Here i can do this.
if btn_clicked == QMessageBox.Save:
print("Close.. After Saving...")
elif btn_clicked == QMessageBox.Close:
print("Close.. Without saving")
else:
print("Cancel.. Don't exit the program")
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = Window()
win.resize(200, 200)
win.show()
sys.exit(app.exec_())
I've found the solution and it worked with me by using a custom signal and slot, but still not sure if it is good or not. waiting for approval and then I can mark this solution as an accepted one.
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class CustomDialog(QDialog):
# Create a signal
signal = pyqtSignal(int)
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle("Data will be lost")
label = QLabel("Are you sure you want close the app before saving?")
self.buttonBox = QDialogButtonBox()
self.buttonBox.addButton(QDialogButtonBox.Save)
self.buttonBox.addButton(QDialogButtonBox.Cancel)
self.buttonBox.addButton(QDialogButtonBox.Close)
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(self.buttonBox)
self.resize(300, 100)
self.setLayout(layout)
# connect each button with custom slot
self.buttonBox.button(QDialogButtonBox.Save).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Save))
self.buttonBox.button(QDialogButtonBox.Close).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Close))
self.buttonBox.button(QDialogButtonBox.Cancel).clicked.connect(lambda: self.customSlot(QDialogButtonBox.Cancel))
# connect signal with buil-in function from QDialog (done())
# This done function will return <int> value and close the dialog.
self.signal.connect(self.done)
def customSlot(self, button_id):
# emit button's id
self.signal.emit(button_id)
class Window(QWidget):
def __init__(self):
super().__init__()
label = QLabel('Hello Dialog', self)
open_dialog_button = QPushButton('Open Dialog', self)
open_dialog_button.clicked.connect(self.showDialog)
layout = QVBoxLayout()
layout.addWidget(label)
layout.addWidget(open_dialog_button)
self.setLayout(layout)
def showDialog(self):
dialog = CustomDialog()
btn_clicked = dialog.exec_() # dialog exec returns button's id
# Now you can use the following lines of code
if btn_clicked == QDialogButtonBox.Save:
print("Close.. After Saving...")
elif btn_clicked == QDialogButtonBox.Close:
print("Close.. Without saving")
else:
print("Cancel.. Don't exit the program")
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
win = Window()
win.resize(200, 200)
win.show()
sys.exit(app.exec_())
i want to change object in all my subwindows
this is my code
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
count = 0
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("Subwindow")
file.addAction("New")
file.addAction("Change Text")
file.triggered[QAction].connect(self.click)
self.setWindowTitle("Multiple window using MDI")
def click(self,action):
print("New sub window")
if action.text() == "New":
MainWindow.count = MainWindow.count + 1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow" + str(MainWindow.count))
self.subwindow = self.mdi.addSubWindow(sub)
self.subwindow.show()
self.label3 = QtWidgets.QLabel(sub)
self.label3.setGeometry(10, 80, 500, 10)
self.label3.setText('Default')
self.label3.show()
if action.text() == "Change Text":
for i in self.mdi.subWindowList():
label1 = QtWidgets.QLabel(i)
label1.setGeometry(10,50,500,10)
label1.setText(str(i))
label1.show()
self.label3.setText('TRUE')
print(i)
def main():
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
but it's always the last creating order subwindow that changes
https://i.stack.imgur.com/DjZtf.png
how to change item in every subwindow?
how to change text table in subwindow i want with over 10 subwindow?
Right now your label3 is stored in MainWindow, so when you cycle through your subwindows you just change the latest label. You can store it in each subwindow like this:
import sys
from PyQt5.QtWidgets import *
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
count = 0
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.mdi = QMdiArea()
self.setCentralWidget(self.mdi)
bar = self.menuBar()
file = bar.addMenu("Subwindow")
file.addAction("New")
file.addAction("Change Text")
file.triggered[QAction].connect(self.click)
self.setWindowTitle("Multiple window using MDI")
def click(self, action):
print("New sub window")
if action.text() == "New":
MainWindow.count = MainWindow.count + 1
sub = QMdiSubWindow()
sub.setWidget(QTextEdit())
sub.setWindowTitle("subwindow" + str(MainWindow.count))
self.subwindow = self.mdi.addSubWindow(sub)
self.subwindow.show()
# change current subwindow label text
button = QPushButton("Click to change", sub)
button.clicked.connect(lambda: sub.label3.setText('TRUE'))
sub.label3 = QtWidgets.QLabel(sub)
sub.label3.setGeometry(10, 80, 500, 10)
sub.label3.setText('Default')
sub_layout = self.subwindow.layout()
sub_layout.addWidget(sub.label3)
sub_layout.addWidget(button)
if action.text() == "Change Text":
for i in self.mdi.subWindowList():
label1 = QtWidgets.QLabel(i)
label1.setGeometry(10, 50, 500, 10)
label1.setText(str(i))
label1.show()
i.label3.setText('TRUE')
print(i)
def main():
app = QApplication(sys.argv)
ex = MainWindow()
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I have created a login window where the window will remain until the user enters the right password, and if the user presses the "X" button on the top right corner, the window should disappear. However, the window disappears even if the user enters the incorrect password.
Code:
class Login(QDialog):
def __init__(self,parent=None):
super(Login, self).__init__(parent)
self.grid = QGridLayout(self)
self.setGeometry(650, 350, 400, 150)
self.setFixedSize(400, 150)
self.UserLabels = QLabel(self)
self.UserLabels.setText('Login Number:')
self.grid.addWidget(self.UserLabels, 0, 0, 1, 1)
self.textName = QLineEdit(self)
self.grid.addWidget(self.textName, 0, 1, 1, 2)
self.buttonLogin = QPushButton('Submit', self)
self.buttonLogin.clicked.connect(self.closeGUI)
self.grid.addWidget(self.buttonLogin, 2, 0, 1, 3)
finish = QAction("Quit", self)
finish.triggered.connect(self.closeWin)
def closeGUI(self):
self.close()
return str(self.textName.text())
def closeWin(self):
self.close()
return 1
def handleLogin():
flag = 0
while flag == 0:
edit_params__QD = Login()
edit_params__QD.exec_()
if edit_params__QD.result() == 0:
password = edit_params__QD.closeGUI()
if password == '6':
flag = 1
else:
flag = 0
if edit_params__QD.closeWin() == 1:
flag = 1
if __name__ == '__main__':
app = QApplication(sys.argv)
handleLogin()
Try it:
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
windowList = []
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('Main interface')
self.showMaximized()
# Create Menu Bar
self.createMenus()
def createMenus(self):
# Create login action
self.printAction1 = QAction(self.tr("Entrance"), self)
self.printAction1.triggered.connect(self.on_printAction1_triggered)
# Create exit action
self.printAction2 = QAction(self.tr("Exit"), self)
self.printAction2.triggered.connect(self.on_printAction2_triggered)
# Create menu, add actions
self.printMenu = self.menuBar().addMenu(self.tr("Entrance and Exit"))
self.printMenu.addAction(self.printAction1)
self.printMenu.addAction(self.printAction2)
# Step 1: Login
def on_printAction1_triggered(self):
self.close()
dialog = LoginDialog()
if dialog.exec_()==QDialog.Accepted:
the_window = MainWindow()
self.windowList.append(the_window) # ! It is important !
the_window.show()
def on_printAction2_triggered(self):
self.close()
# Interface close event
def closeEvent(self, event):
print("The End")
class LoginDialog(QDialog):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.setWindowTitle('Login interface')
self.resize(250, 200)
self.setFixedSize(self.width(), self.height())
self.setWindowFlags(Qt.WindowCloseButtonHint)
# Configure UI controls
self.frame = QFrame(self)
self.frame.resize(250, 200)
self.verticalLayout = QVBoxLayout(self.frame)
self.lineEdit_account = QLineEdit()
self.lineEdit_account.setPlaceholderText("Please enter nickName (admin)")
self.verticalLayout.addWidget(self.lineEdit_account)
self.lineEdit_password = QLineEdit()
self.lineEdit_password.setPlaceholderText("Please enter your password (admin)")
self.verticalLayout.addWidget(self.lineEdit_password)
self.pushButton_enter = QPushButton()
self.pushButton_enter.setText("OK")
self.verticalLayout.addWidget(self.pushButton_enter)
self.pushButton_quit = QPushButton()
self.pushButton_quit.setText("Cancel")
self.verticalLayout.addWidget(self.pushButton_quit)
# bindings button Event
self.pushButton_enter.clicked.connect(self.on_pushButton_enter_clicked)
self.pushButton_quit.clicked.connect(QCoreApplication.instance().quit)
def on_pushButton_enter_clicked(self):
# Check nickName
if self.lineEdit_account.text() != "admin":
return
# Check password
if self.lineEdit_password.text() != "admin":
return
# Close the dialog and return 1 when checking
self.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
dialog = LoginDialog()
if dialog.exec_()==QDialog.Accepted:
the_window = MainWindow()
the_window.show()
sys.exit(app.exec_())
A more complete example showing how to write a login dialog is given here:
Login dialog PyQt
However, in your own example, you should note that It's not necessary to handle the close-event, because the "X" button will automatically
set the dialog's result to Rejected. Instead, you just need to set the result to Accepted when the submit button is clicked. You can then check the return value of exec_() to see what the user did.
Here is a re-write of your script that does that:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class Login(QDialog):
def __init__(self,parent=None):
super(Login, self).__init__(parent)
self.grid = QGridLayout(self)
self.setGeometry(650, 350, 400, 150)
self.setFixedSize(400, 150)
self.UserLabels = QLabel(self)
self.UserLabels.setText('Login Number:')
self.grid.addWidget(self.UserLabels, 0, 0, 1, 1)
self.textName = QLineEdit(self)
self.grid.addWidget(self.textName, 0, 1, 1, 2)
self.buttonLogin = QPushButton('Submit', self)
self.buttonLogin.clicked.connect(self.accept)
self.grid.addWidget(self.buttonLogin, 2, 0, 1, 3)
def password(self):
return self.textName.text()
def handleLogin():
result = None
login = Login()
while result is None:
if login.exec_() == QDialog.Accepted:
password = login.password()
if password == '6':
result = True
else:
result = False
return result
if __name__ == '__main__':
app = QApplication(sys.argv)
if handleLogin():
print('logged in')
else:
print('cancelled')
How can I change the text displayed in the second column of the rows selected in the treeview when the user hits 'Edit' in the UI? I'm using python and pyside but I'm not clear on how to do this.
What I want to happen is: When user clicks Edit in the UI i would like it to change the text of the selected Treeview Rows second columns. You can just change the text to say 'Hello' or something simple.
import sys
from PySide import QtGui, QtCore
class SortModel(QtGui.QSortFilterProxyModel):
def __init__(self, *args, **kwargs):
super(SortModel, self).__init__(*args, **kwargs)
def lessThan(self, left, right):
leftData = self.sourceModel().data(left)
rightData = self.sourceModel().data(right)
if leftData:
leftData = leftData.lower()
if rightData:
rightData = rightData.lower()
print('L:', leftData, 'R:', rightData)
return leftData < rightData
class Browser(QtGui.QDialog):
def __init__(self, parent=None):
super(Browser, self).__init__(parent)
self.initUI()
def initUI(self):
self.resize(200, 300)
self.setWindowTitle('Assets')
self.setModal(True)
self.results = ""
self.uiItems = QtGui.QTreeView()
self.uiItems.setAlternatingRowColors(True)
self.uiItems.setSortingEnabled(True)
self.uiItems.sortByColumn(0, QtCore.Qt.AscendingOrder)
self.uiItems.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
self.uiItems.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
self.uiItems.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
self.uiItems.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
self._model = self.create_model(self)
self._spmodel = SortModel(self)
self._spmodel.setSourceModel(self._model)
self._spmodel.setDynamicSortFilter(False)
self.uiItems.setModel(self._spmodel)
self.uiEdit = QtGui.QPushButton('Edit')
grid = QtGui.QGridLayout()
grid.setContentsMargins(0, 0, 0, 0)
grid.addWidget(self.uiItems, 0, 0)
grid.addWidget(self.uiEdit, 1, 0)
self.setLayout(grid)
self.uiItems.doubleClicked.connect(self.doubleClickedItem)
self.show()
def doubleClickedItem(self, idx):
name = idx.data(role=QtCore.Qt.DisplayRole)
model = idx.model()
model.setData(idx, 'great', role=QtCore.Qt.DisplayRole)
def create_model(self, parent):
items = [
'Cookie dough',
'Hummus',
'Spaghetti',
'Dal makhani',
'Chocolate whipped cream'
]
model = QtGui.QStandardItemModel()
model.setHorizontalHeaderLabels(['Name', 'Great'])
for item in items:
root = []
parentNode = QtGui.QStandardItem(item)
root.append(parentNode)
# add child row with 2 columns
for i in range(3):
row = []
col1 = QtGui.QStandardItem()
col1.setData('COLUMN 1', role=QtCore.Qt.DisplayRole)
row.append(col1)
col2 = QtGui.QStandardItem()
col2.setData('COLUMN 2', role=QtCore.Qt.DisplayRole)
row.append(col2)
parentNode.appendRow(row)
model.appendRow(root)
return model
def showEvent(self, event):
geom = self.frameGeometry()
geom.moveCenter(QtGui.QCursor.pos())
self.setGeometry(geom)
super(Browser, self).showEvent(event)
def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
# self.hide()
self.close()
event.accept()
else:
super(Browser, self).keyPressEvent(event)
def main():
app = QtGui.QApplication(sys.argv)
ex = Browser()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Connect the button’s clicked signal, retrieve the selected items via model.selectedIndexes, iterate over them and only handle those with .column()== 1 as in your doubleClickedItem function.
You can also change the SelectionBehavior to only select single items instead of complete rows.