Is there a way to send a PySide2 model through subproces.Popen? - python

In my MainApp I have a QTreeView populated by items from a QStandardItemModel. By clicking a button I use subprocess.Popen to launch a 3D software (in this case Maya2020). Once Maya is running I execute a snippet of code inside of its script editor to open a widget called SubApp.
I'd like to pass MainApp's model data to SubApp's QTreeView somehow. In my real code when I launch SubApp I use environment variables to send some key values (UUID and list of UUID parents) to reconstruct the model/view again. This feels over complicated and I'm wondering if there's a better way to share data?
My code: (Note! I've included MainApp and SubApp in the same module for simplicity, but these classes are decoupled in the real thing)
main_launch.py
import os
import sys
import subprocess
from Qt import QtWidgets, QtGui
class MainApp(QtWidgets.QWidget):
""" This is the main launcher app that holds the model data
"""
def __init__(self, parent=None):
super(MainApp, self).__init__(parent)
# Model/View
view = QtWidgets.QTreeView()
model = QtGui.QStandardItemModel()
view.setModel(model)
# Populate data
for i in range(3):
parent1 = QtGui.QStandardItem('Parent {}'.format(i))
for j in range(3):
child1 = QtGui.QStandardItem('Child {}'.format(i * 3 + j))
child2 = QtGui.QStandardItem('row: {}, col: {}'.format(i, j + 1))
child3 = QtGui.QStandardItem('row: {}, col: {}'.format(i, j + 2))
parent1.appendRow([child1, child2, child3])
model.appendRow(parent1)
# span container columns
view.setFirstColumnSpanned(i, view.rootIndex(), True)
# GUI
btn_launch = QtWidgets.QPushButton('launch sub app')
btn_launch.clicked.connect(self.on_launch_sub_app)
# Layout
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.addWidget(view)
main_layout.addWidget(btn_launch)
self.setLayout(main_layout)
self.root_path = os.path.join(os.path.dirname(os.path.realpath(__file__))).replace('\\', '/')
# Copy this path when it prints and paste it into "maya_snippet"s "root_path"
print(self.root_path)
def on_launch_sub_app(self):
""" Opens software (maya in this case) and then you launch SubApp from within maya's script editor.
Is there any way to send the model data using subprocess.Popen?
"""
# Maya location
app_exe = r'C:/Program Files/Autodesk/Maya2020/bin/maya.exe'
proc = subprocess.Popen(
[app_exe]
)
class SubApp(QtWidgets.QWidget):
""" Running the "maya_snippet.py" code from within maya will launch this window
"""
def __init__(self, parent=None):
super(SubApp, self).__init__(parent)
# Model/View
view = QtWidgets.QTreeView()
# Would like to set the model from the MainApp
model = QtGui.QStandardItemModel()
view.setModel(model)
# Layout
main_layout = QtWidgets.QHBoxLayout(self)
main_layout.addWidget(view)
self.setLayout(main_layout)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MainApp()
window.resize(400, 400)
window.show()
sys.exit(app.exec_())
maya_snippet.py (Run this from within Maya to launch SubApp (after you've launched Maya from MainApp))
import sys
# Change root_path to the directory holding main_launch.py
root_path = 'path/to/directory/holding/main_launch'
if not root_path in sys.path:
sys.path.append(root_path.replace('\\', '/')
import main_launch
w = main_launch.SubApp()
w.show()

Related

Increase frame rate for QCamera/QCameraViewfinder using PySide2 (Qt5)

I'm tying to create a simple application to monitor a webcam and taking pictures, basically following the Qt for Python Camera Example, which uses PySide6 (Qt6).
However, for my case, I must use PySide2 (Qt5) instead, as the embed computer for this application has i386 architecture (32-bit Debian 11 installed). This is a small (working) sample code:
from pathlib import Path
from tempfile import NamedTemporaryFile
from PySide2 import QtWidgets, QtMultimedia, QtMultimediaWidgets
class SimpleCameraGUI(QtWidgets.QMainWindow):
def __init__(self):
super(SimpleCameraGUI, self).__init__(None)
# main GUI elelements
central_widget = QtWidgets.QWidget()
hlayout = QtWidgets.QHBoxLayout()
vlayout = QtWidgets.QVBoxLayout()
self.start = QtWidgets.QPushButton('Start camera')
self.stop = QtWidgets.QPushButton('Stop camera')
self.take_pic = QtWidgets.QPushButton('Take Picture')
self.camera_widget = QtMultimediaWidgets.QCameraViewfinder()
# elements to Layout
hlayout.addWidget(self.start)
hlayout.addWidget(self.stop)
hlayout.addWidget(self.take_pic)
vlayout.addWidget(self.camera_widget)
vlayout.addLayout(hlayout)
central_widget.setLayout(vlayout)
self.setCentralWidget(central_widget)
# camera elements
self.info = QtMultimedia.QCameraInfo()
self.camera = QtMultimedia.QCamera(self.info.defaultCamera())
self.image = QtMultimedia.QCameraImageCapture(self.camera)
self.camera.setViewfinder(self.camera_widget)
# connections
self.start.clicked.connect(self.camera.start)
self.stop.clicked.connect(self.camera.stop)
self.take_pic.clicked.connect(self.save_temp_picture)
# show GUI
self.show()
def save_temp_picture(self):
filename = NamedTemporaryFile(suffix='.jpg', delete=True)
self.image.capture(filename.name)
QtWidgets.QMessageBox.information(
None,
'Temporary file saved',
f'Location: <a href={Path(filename.name).as_uri()}>{filename.name}</a>'
)
if __name__ == '__main__':
app = QtWidgets.QApplication()
win = SimpleCameraGUI()
win.resize(640, 480)
app.exec_()
The application works fine, but the video inside the QCameraViewfinder widget is extremely slow. I believe it has something to do with frame rate settings, but couldn't find where/how to change the parameters. My PySide2 version is 5.15.2.1.
Tried to use a QVideoWidget, but results are the same. Also tried to use the method setViewfinderSettings of the QCamera, but couldn't figure out how to actually use it.
After some searching I did found a solution.
One must create a QCameraViewfinderSettings object, set the desired frame rate range using setMinimumFrameRate() and setMaximumFrameRate() methods and finally apply those settings to the QCamera using setViewfinderSettings() method. I also discovered that it is important to choose the proper resolution of your camera by using setResolution().
Below is a revised code:
from pathlib import Path
from tempfile import NamedTemporaryFile
from PySide2 import QtWidgets, QtMultimedia, QtMultimediaWidgets
class SimpleCameraGUI(QtWidgets.QMainWindow):
def __init__(self):
super(SimpleCameraGUI, self).__init__(None)
# main GUI elelements
central_widget = QtWidgets.QWidget()
hlayout = QtWidgets.QHBoxLayout()
vlayout = QtWidgets.QVBoxLayout()
self.start = QtWidgets.QPushButton('Start camera')
self.stop = QtWidgets.QPushButton('Stop camera')
self.take_pic = QtWidgets.QPushButton('Take Picture')
self.camera_widget = QtMultimediaWidgets.QCameraViewfinder()
# elements to Layout
hlayout.addWidget(self.start)
hlayout.addWidget(self.stop)
hlayout.addWidget(self.take_pic)
vlayout.addWidget(self.camera_widget)
vlayout.addLayout(hlayout)
central_widget.setLayout(vlayout)
self.setCentralWidget(central_widget)
# camera elements
self.info = QtMultimedia.QCameraInfo()
self.camera = QtMultimedia.QCamera(self.info.defaultCamera())
self.image = QtMultimedia.QCameraImageCapture(self.camera)
self.camera.setViewfinder(self.camera_widget)
# sets resolution and frame rate to camera/viewfinder
self.settings = QtMultimedia.QCameraViewfinderSettings()
self.settings.setResolution(640, 480)
self.settings.setMinimumFrameRate(15)
self.settings.setMaximumFrameRate(30)
self.camera.setViewfinderSettings(self.settings)
# connections
self.start.clicked.connect(self.camera.start)
self.stop.clicked.connect(self.camera.stop)
self.take_pic.clicked.connect(self.save_temp_picture)
# show GUI
self.show()
def save_temp_picture(self):
filename = NamedTemporaryFile(suffix='.jpg', delete=True)
self.image.capture(filename.name)
QtWidgets.QMessageBox.information(
None,
'Temporary file saved',
f'Location: <a href={Path(filename.name).as_uri()}>{filename.name}</a>'
)
if __name__ == '__main__':
app = QtWidgets.QApplication()
win = SimpleCameraGUI()
win.resize(640, 480)
app.exec_()

Program crashes when filtering QFileSystemModel and using filePath function [duplicate]

I have QfileSysteModel and QSortFilterProxyModel. When I try to call QfileSysteModel.filePath to get the current index of the file Error occurs as core Dump. Here is a piece of code
le = QLineEdit()
lv = QListView()
file_model = QFileSystemModel()
file_model.setRootPath(QtCore.QDir.rootPath())
proxy_model = QSortFilterProxyModel(
recursiveFilteringEnabled=True,
filterRole=QtWidgets.QFileSystemModel.FileNameRole)
proxy_model.setSourceModel(file_model)
lv.setModel(self.proxy_model)
It works well, but when I try to call any methods of the QFileSystemModel Core Dumps. for example
filepath = file_model.filePath(lv.currentIndex())
How can I use any method of the QfileSystemModel
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
le = QtWidgets.QLineEdit()
self.lv = QtWidgets.QListView()
self.file_model = QtWidgets.QFileSystemModel()
self.file_model.setRootPath(QtCore.QDir.rootPath())
self.proxy_model = QtCore.QSortFilterProxyModel(
recursiveFilteringEnabled=True,
filterRole=QtWidgets.QFileSystemModel.FileNameRole)
self.proxy_model.setSourceModel(self.file_model)
self.lv.setModel(self.proxy_model)
root_index = self.file_model.index(QtCore.QDir.rootPath())
proxy_index = self.proxy_model.mapFromSource(root_index)
self.lv.setRootIndex(proxy_index)
self.lv.doubleClicked.connect(self.navigate)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(le)
lay.addWidget(self.lv)
def navigate(self):
# Get the path of file or folder
filepath = self.file_model.filePath(self.lv.currentIndex())
print(filepath)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
When working with a proxy model, the ModelIndex of the proxy differs from the index in the source model. Use mapToSource() to convert from proxy model to source model.
In your case, it would probably look like this:
# alternative one: do not reference proxy_model directly
filepath = file_model.filePath(lv.model().mapToSource(lv.currentIndex()))
# alternative two:
filepath = file_model.filePath(self.proxy_model.mapToSource(lv.currentIndex()))

Proper way to pass an infromation/variable across QTabWidgets?

EDIT: Changed title, few mistakes in code were resolved (now working properly)
The GUI I am trying to make will be a simple QTabWidget, leading a user straightforwardly towards the end tab by tab.
For now, I have three *.py files - main.py, tab1.py, tab2.py. In main.py is the main window of the app and function to run the app like this (simplified just to focus on my question):
import sys
import tab1
import tab2
import PyQt5.QtWidgets as qtw
def main():
app = qtw.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
class MainWindow(qtw.QmainWindow):
def __init__(self):
super().__init__()
self.tabwidget = qtw.QTabWidget()
self.setCentralWidget(self.tabwidget)
self.tab1 = tab1.Tab_1()
self.tab2 = tab2.Tab_2()
# This is how I now passing the information from tab1 to tab2
self.tab1.path_line.textChanged.connect(self.tab2.path_widget.setText)
self.tabwidget.addTab(self.tab1, 'tab1')
self.tabwidget.addTab(self.tab2, 'tab2')
if __name__ == '__main__':
main()
In the tab1.py is a defined class for a tabwidget which will serve as an input data tab. There is a button to open filedialog, read filename, and write the path into the QLineEdit widget:
import PyQt5.QtWidgets as qtw
class Tab_1(qtw.QWidget):
def __init__(self):
super().__init__()
self.path_line = qtw.QLineEdit()
self.but = qtw.QPushButton('Open')
self.but.clicked.connect(self.openfile)
layout_1 = qtw.QVBoxLayout()
layout_1.addWidget(self.but)
self.setLayout(layout_1)
def openfile(self):
filename, _ = qtw.QFileDialog.getOpenFileName(self, 'Title', 'File types')
if filename:
self.path_line.setText(filename)
else:
self.path_line.setText('No file was selected!')
Now I want to in another file tab2.py use the path I got from qtw.OpenFileDialog. So the defined class Tab_2() looks like this:
import PyQt5.QtWidgets as qtw
class Tab_2(qtw.QWidget):
def __init__(self):
super().__init__()
# Retrieving the information by QLabel widget
self.path_widget = qtw.QLabel()
# Transform the information into string variable
self.path_string = self.path_widget.text()
layout_2 = qtw.QVBoxLayout()
layout_2.addWidget(self.path_widget) # The path from QFileDialog (Tab1) should appered on Tab2
self.setLayout(layout_2)
My question is, is this the proper way to do it? Should I use MainWindow class as a "getter" and "passer" of the information like that or should that be implemented in the tab classes themselves? It works but I do not want to learn to do something bad way and eventually get used to it. I understand classes and their inheritance to some point (a lot of examples of dog classes or employee classes which I understand how it works but in my case I am confused.). In combination with GUI, it messing up my head. Also, I want to have each tab as a separate class in a separate *.py file to make it clear and easy to add another one in the future. I see, that it might not be the right way to uses classes but each tab will have a different layout.
After some testing, I found out that the best way to pass variable across QTabWidgets is, in my case, by class inheritence. For this idea, thanks to #S. Nick from Code Review.
I have main.py for the QMainWindow of the app and then two another *.py files, each containing a TabWidget class. Since I am creating imported Tab widgets classes in the main.py, the best solution for my question was to save a variable into the QMainWindow and then access it via Tab classes through the "self-parent thing". I am really a programming beginner, therefore I do not know if this is a basic knowledge or not. But by storing a variable into the parent QMainWindow class I can access it from any widget class created in the QMainWindow by including the "self" parameter. Here is the variance of the final code I used:
import sys
import PyQt5.QtWidgets as qtw
#from tab1 import Tab_1
class Tab_1(qtw.QWidget):
""" In this class I obtain a file path """
def __init__(self, parent=None): # + parent
super().__init__()
self.parent = parent # + parent
self.but_1 = qtw.QPushButton('Open')
self.but_1.clicked.connect(self.open_file)
layout_1 = qtw.QVBoxLayout(self)
layout_1.addWidget(self.but_1)
self.setLayout(layout_1)
def open_file(self):
filename, _ = qtw.QFileDialog.getOpenFileName(self, 'Title', 'File types')
if filename:
self.parent.file_path = filename # + parent
else:
self.parent.file_path = 'No file was selected' # + parent
#from tab2 import Tab_2
class Tab_2(qtw.QWidget):
""" In this class I want to use the file path from Tab 1 """
def __init__(self, parent=None): # + parent
super().__init__()
self.parent = parent # + parent
self.but_2 = qtw.QPushButton('Load path')
self.but_2.clicked.connect(self._load_path)
self.path_widget = qtw.QLabel('') # will show path to file after the button-click
layout_2 = qtw.QVBoxLayout(self)
layout_2.addWidget(self.but_2)
layout_2.addWidget(self.path_widget)
self.setLayout(layout_2)
def _load_path(self):
self.path_widget.setText(self.parent.file_path)
class MainWindow(qtw.QMainWindow):
def __init__(self):
super().__init__()
self.file_path = '' # + file_path
self.tabwidget = qtw.QTabWidget()
self.setCentralWidget(self.tabwidget)
self.tab1 = Tab_1(self) # + self
self.tab2 = Tab_2(self) # + self
self.tabwidget.addTab(self.tab1, 'Tab 1')
self.tabwidget.addTab(self.tab2, 'Tab 2')
def main():
app = qtw.QApplication(sys.argv)
window = MainWindow()
window.resize(400, 300)
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

QFileDialog.getOpenFileName change button text from 'Open' to 'Remove'

I am using QFileDialog.getOpenFileName(self,'Remove File', "path", '*.pdf') to select a file and get the path in order to remove it from my application. The issue is the QFileDialog.getOpenFileName window button says 'Open' when selecting a file which will be confusing to the user.
Is there any way to change the button text from 'Open' to 'Remove'/'Delete'
When using the static method QFileDialog::getOpenFileName() the first thing is to obtain the QFileDialog object and for that we use a QTimer and the findChild() method:
# ...
QtCore.QTimer.singleShot(0, self.on_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(...,
options=QtWidgets.QFileDialog.DontUseNativeDialog)
def on_timeout(self):
dialog = self.findChild(QtWidgets.QFileDialog)
# ...
Then you can get the text iterating over the buttons until you get the button with the searched text and change it:
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == "&Open":
btn.setText("Remove")
That will work at the beginning but every time you interact with the QTreeView they show, update the text to the default value, so the same logic will have to be applied using the currentChanged signal from the selectionModel() of the QTreeView but for synchronization reasons it is necessary Update the text later using another QTimer.singleShot(), the following code is a workable example:
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Press me")
button.clicked.connect(self.on_clicked)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
#QtCore.pyqtSlot()
def on_clicked(self):
QtCore.QTimer.singleShot(0, self.on_timeout)
filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self,
"Remove File",
"path",
"*.pdf",
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
def on_timeout(self):
dialog = self.findChild(QtWidgets.QFileDialog)
dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
lambda: self.change_button_name(dialog)
)
self.change_button_name(dialog)
def change_button_name(self, dialog):
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == self.tr("&Open"):
QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
The first step can be avoided if the static method is not used and create the dialog using an instance of QFileDialog:
import sys
from PyQt5 import QtCore, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Press me")
button.clicked.connect(self.on_clicked)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(button)
#QtCore.pyqtSlot()
def on_clicked(self):
dialog = QtWidgets.QFileDialog(
self,
"Remove File",
"path",
"*.pdf",
supportedSchemes=["file"],
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
self.change_button_name(dialog)
dialog.findChild(QtWidgets.QTreeView).selectionModel().currentChanged.connect(
lambda: self.change_button_name(dialog)
)
if dialog.exec_() == QtWidgets.QDialog.Accepted:
filename = dialog.selectedUrls()[0]
print(filename)
def change_button_name(self, dialog):
for btn in dialog.findChildren(QtWidgets.QPushButton):
if btn.text() == self.tr("&Open"):
QtCore.QTimer.singleShot(0, lambda btn=btn: btn.setText("Remove"))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
While I appreciate the solution provided by #eyllanesc, I'd like to propose a variation.
Under certain circumstances, the code for that answer might fail, specifically:
the delay that X11 suffers from mapping windows;
the checking of localized button strings;
the selection using the file name edit box;
Considering the above, I propose an alternate solution, based on the points above.
For obvious reasons, the main point remains: the dialog must be non-native.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class FileDialogTest(QWidget):
def __init__(self):
super().__init__()
layout = QHBoxLayout(self)
self.fileEdit = QLineEdit()
layout.addWidget(self.fileEdit)
self.selectBtn = QToolButton(icon=QIcon.fromTheme('folder'), text='…')
layout.addWidget(self.selectBtn)
self.selectBtn.clicked.connect(self.showSelectDialog)
def checkSelectDialog(self):
dialog = self.findChild(QFileDialog)
if not dialog.isVisible():
# wait for dialog finalization, as testOption might fail
return
# dialog found, stop the timer and delete it
self.sender().stop()
self.sender().deleteLater()
if not dialog.testOption(dialog.DontUseNativeDialog):
# native dialog, we cannot do anything!
return
def updateOpenButton():
selection = tree.selectionModel().selectedIndexes()
if selection and not tree.model().isDir(selection[0]):
# it's a file, change the button text
button.setText('Select my precious file')
tree = dialog.findChild(QTreeView)
button = dialog.findChild(QDialogButtonBox).button(
QDialogButtonBox.Open)
# check for selected files on open
updateOpenButton()
# connect the selection update signal
tree.selectionModel().selectionChanged.connect(
lambda: QTimer.singleShot(0, updateOpenButton))
def showSelectDialog(self):
QTimer(self, interval=10, timeout=self.checkSelectDialog).start()
path, filter = QFileDialog.getOpenFileName(self,
'Select file', '<path_to_file>',
"All Files (*);;Python Files (*.py);; PNG Files (*.png)",
options=QFileDialog.DontUseNativeDialog)
if path:
self.fileEdit.setText(path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
ex = FileDialogTest()
ex.show()
sys.exit(app.exec())
Obviously, for PyQt6 you'll need to use the proper Enum namespaces (i.e. QFileDialog.Option.DontUseNativeDialog, etc.).

Python: PyQt QTreeview example - selection

I'm using Python 2.7 and Qt designer and I'm new to MVC:
I have a View completed within Qt to give me a directory tree list, and the controller in place to run things. My question is:
Given a Qtree view, how may I obtain a directory once a dir is selected?
Code snap shot is below, I suspect it's SIGNAL(..) though I'm unsure:
class Main(QtGui.QMainWindow):
plot = pyqtSignal()
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# create model
model = QtGui.QFileSystemModel()
model.setRootPath( QtCore.QDir.currentPath() )
# set the model
self.ui.treeView.setModel(model)
**QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)**
def test(self):
print "hello!"
The signal you're looking for is selectionChanged emmited by the selectionModel owned by your tree. This signal is emmited with the selected item as first argument and the deselected as second, both are instances of QItemSelection.
So you might want to change the line:
QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)
to
QtCore.QObject.connect(self.ui.treeView.selectionModel(), QtCore.SIGNAL('selectionChanged()'), self.test)
Also I recommend you to use the new style for signals and slots. Redefine your test function as:
#QtCore.pyqtSlot("QItemSelection, QItemSelection")
def test(self, selected, deselected):
print("hello!")
print(selected)
print(deselected)
Here you have a working example:
from PyQt4 import QtGui
from PyQt4 import QtCore
class Main(QtGui.QTreeView):
def __init__(self):
QtGui.QTreeView.__init__(self)
model = QtGui.QFileSystemModel()
model.setRootPath( QtCore.QDir.currentPath() )
self.setModel(model)
QtCore.QObject.connect(self.selectionModel(), QtCore.SIGNAL('selectionChanged(QItemSelection, QItemSelection)'), self.test)
#QtCore.pyqtSlot("QItemSelection, QItemSelection")
def test(self, selected, deselected):
print("hello!")
print(selected)
print(deselected)
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
PyQt5
In PyQt5 is a little bit different (thanks to Carel and saldenisov for comments and aswer.)
... connect moved from being an object method to a method acting upon the attribute when PyQt went from 4 to 5
So instead the known:
QtCore.QObject.connect(self.ui.treeView, QtCore.SIGNAL('clicked()'), self.test)
now you write:
class Main(QTreeView):
def __init__(self):
# ...
self.setModel(model)
self.doubleClicked.connect(self.test) # Note that the the signal is now a attribute of the widget.
Here is a the example (by saldenisov) using PyQt5.
from PyQt5.QtWidgets import QTreeView,QFileSystemModel,QApplication
class Main(QTreeView):
def __init__(self):
QTreeView.__init__(self)
model = QFileSystemModel()
model.setRootPath('C:\\')
self.setModel(model)
self.doubleClicked.connect(self.test)
def test(self, signal):
file_path=self.model().filePath(signal)
print(file_path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
In PyQt5 it can be done in this way:
from PyQt5.QtWidgets import QTreeView,QFileSystemModel,QApplication
class Main(QTreeView):
def __init__(self):
QTreeView.__init__(self)
model = QFileSystemModel()
model.setRootPath('C:\\')
self.setModel(model)
self.doubleClicked.connect(self.test)
def test(self, signal):
file_path=self.model().filePath(signal)
print(file_path)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(app.exec_())
If I understand the question correctly you would like the directory or file name selected.
This is what I do:
from PyQt4 import QtGui
from PyQt4 import QtCore
# ---------------------------------------------------------------------
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.resize(600,400)
self.setWindowTitle("Treeview Example")
self.treeview = QtGui.QTreeView(self)
self.treeview.model = QtGui.QFileSystemModel()
self.treeview.model.setRootPath( QtCore.QDir.currentPath() )
self.treeview.setModel(self.treeview.model)
self.treeview.setColumnWidth(0, 200)
self.setCentralWidget(self.treeview)
self.treeview.clicked.connect(self.on_treeview_clicked)
# ---------------------------------------------------------------------
#QtCore.pyqtSlot(QtCore.QModelIndex)
def on_treeview_clicked(self, index):
indexItem = self.treeview.model.index(index.row(), 0, index.parent())
# path or filename selected
fileName = self.treeview.model.fileName(indexItem)
# full path/filename selected
filePath = self.treeview.model.filePath(indexItem)
print(fileName)
print(filePath)
# ---------------------------------------------------------------------
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I tried this alternative to get the file name...
Instead of:
indexItem = self.treeview.model.index(index.row(), 0, index.parent())
# path or filename selected
fileName = self.treeview.model.fileName(indexItem)
I tried:
# path or filename selected
fileName = index.internalPointer().fileName
Which also seems to work...

Categories

Resources