How can I use a QTextBrowser instead of the console in Python? - python

I've constructed a window in PyQt 5, which by clicking on the "optimize" button, the program reads the "Gurobi-model.lp" file (click here to get the file), and optimizes it by the help of the Gurobi software. How can I display the logs of the Gurobi on a QTextBrowser?
I found some functions in the Gurobi such as OutputFlag, LogFile, and LogToConsole. Might these functions be helpful not?
For those who are not familiar with Gurobi, the Gurobi optimizer uses Python as an interface, and produces some logs that allows you to track the progress of the optimization. These logs are printed in the console during the optimization, and somehow, responding my question doesn't need to know anything about the Gurobi.
In the below code, I've found a way to show the logs in the QTextBrowser, but the logs are represented when the optimization process is completely done. I want the logs to be represented exactly during the optimization process.
import sys
from PyQt5.QtWidgets import *
from gurobipy import *
from io import *
class MyWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.pb = QPushButton(self.tr("optimize"))
self.log_text = QTextBrowser()
layout = QVBoxLayout(self)
layout.addWidget(self.pb)
layout.addWidget(self.log_text)
self.setLayout(layout)
self.pb.clicked.connect(self.optimize)
def optimize(self):
f = StringIO()
sys.stdout = StringIO()
self.m = read('Gurobi-model.lp')
self.m.optimize()
self.log_text.append(sys.stdout.getvalue() )
def main():
app = QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

The task of optimizing is heavy, so it should not be executed in the same thread of the GUI, nor in the same process. For this you should use the multiprocessing module. On the other hand, if you need to show the output of the console in the QTextBrowser, you must use the logging module, passing it through signal (for the last part, use the answer of this post).
import sys
import logging
import multiprocessing
from logging.handlers import QueueHandler, QueueListener
from PyQt5 import QtCore, QtWidgets
from gurobipy import *
class LogEmitter(QtCore.QObject):
sigLog = QtCore.pyqtSignal(str)
class LogHandler(logging.Handler):
def __init__(self):
super().__init__()
self.emitter = LogEmitter()
def emit(self, record):
msg = self.format(record)
self.emitter.sigLog.emit(msg)
def long_task():
m = read('Gurobi-model.lp')
m.optimize()
def worker_init(q):
qh = QueueHandler(q)
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(qh)
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pb = QtWidgets.QPushButton(self.tr("optimize"),
clicked=self.start_optimize)
self.log_text = QtWidgets.QPlainTextEdit(readOnly=True)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.pb)
layout.addWidget(self.log_text)
self.running = False
handler = LogHandler()
handler.emitter.sigLog.connect(self.log_text.appendPlainText)
self.q = multiprocessing.Queue()
self.ql = QueueListener(self.q, handler)
self.ql.start()
self.main_log = logging.getLogger('main')
self.main_log.propagate = False
self.main_log.setLevel(logging.INFO)
self.main_log.addHandler(QueueHandler(self.q))
self.pool = multiprocessing.Pool(1, worker_init, [self.q])
#QtCore.pyqtSlot()
def start_optimize(self):
if not self.running:
self.pool.apply_async(long_task, callback=self.handle_result)
def handle_result(self, result=None):
self.running = False
def closeEvent(self, event):
self.ql.stop()
super(MyWindow, self).closeEvent(event)
def main():
app = QtWidgets.QApplication(sys.argv)
w = MyWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Related

How to use QMutex correctly with QThread?

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import time
import sys
import numpy as np
class Mainthread(QThread):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.running = None
self.mutex = QMutex()
def run(self):
while self.running:
self.mutex.lock()
print ("test")
time.sleep(1)
self.mutex.unlock()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.mainthread = Mainthread(self)
self.mainthread.running = True
self.mainthread.start()
self.mainthread1 = Mainthread(self)
self.mainthread1.running = True
self.mainthread1.start()
app = QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.show()
app.exec_()
I have this code where I run two instances of the same MainThread class.
What I was expecting was that mainthread's message (which is "test") would print, then wait for a sec and then mainthread1's would be printed. Instead, it seems like both threads are running at the same time. Is there something I'm missing?
In your code, each thread creates its own separate mutex, so no relation is enforced between the two. Create a single mutex first, and pass it to the theads:
import time
import sys
from PyQt5.QtCore import QThread, QMutex
from PyQt5.QtWidgets import QMainWindow, QApplication
class Mainthread(QThread):
def __init__(self, mutex, parent):
super().__init__(parent)
self.parent = parent
self.running = None
self.mutex = mutex
def run(self):
while self.running:
self.mutex.lock()
print ("test")
time.sleep(1)
self.mutex.unlock()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
mutex = QMutex()
self.mainthread = Mainthread(mutex, self)
self.mainthread.running = True
self.mainthread.start()
self.mainthread1 = Mainthread(mutex, self)
self.mainthread1.running = True
self.mainthread1.start()
app = QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.show()
app.exec_()
Note: I don't have PyQt5 installed (and doing so on my architecture is tricky), but I tested this in PySide6 and as far as I know the behavior should be consistent.

Windump via a python subprocess and PyQt Button

The simple idea is that user inputs duration in seconds, and presses a PyQt button, that calls a function that creates a python subprocess and runs windump via it. Then time sleep is used to wait for user defined duration and then process.terminate(), terminates it (code below)
def windump_exec(duration):
p = s.Popen(['windump', '-i', '3', '-w', 'packets.pcap'], stdout=s.PIPE)
time.sleep(duration)
p.terminate()
Now once this is done, scapy reads .pcap file and I show stuff on the screen in short. While this is happening QWaitingSpinner is running, and to handle this I run the above logic (including scapy) using QRunnable (code below)
class ThreadRunnable(QRunnable):
def __init__(self, _time, filler):
QRunnable.__init__(self)
self.time = _time
self.filler = filler
self.signal = RunnableSignal()
def run(self):
windump_exec(self.time)
packets = parse_data()
self.filler(packets)
self.signal.result.emit()
The Problem is that the windump code works fine on it's own, but inside the QThread it doesn't create an output file and hence scapy has nothing to read (open), and it gives error.
Instead of using Popen with QThread you can use QProcess, in my test I have used tcpdump but I suppose that changing to windump should have the same behavior:
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from scapy.all import rdpcap
import psutil
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class DumpProcesor(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._process = QtCore.QProcess()
self._timer = QtCore.QTimer(singleShot=True)
self._timer.timeout.connect(self.handle_timeout)
self._pid = -1
#property
def process(self):
return self._process
#property
def timer(self):
return self._timer
#QtCore.pyqtSlot()
def start(self):
self.started.emit()
status, self._pid = self._process.startDetached()
if status:
self._timer.start()
else:
self.finished.emit()
#QtCore.pyqtSlot()
def handle_timeout(self):
if self._pid > 0:
p = psutil.Process(self._pid)
p.terminate()
QtCore.QTimer.singleShot(100, self.finished.emit)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.log_te = QtWidgets.QTextEdit(readOnly=True)
self.time_sb = QtWidgets.QSpinBox(minimum=1)
self.start_btn = QtWidgets.QPushButton(self.tr("Start"))
grid_layout = QtWidgets.QGridLayout(self)
grid_layout.addWidget(self.log_te, 0, 0, 1, 3)
grid_layout.addWidget(QtWidgets.QLabel("Time (seg):"), 1, 0)
grid_layout.addWidget(self.time_sb, 1, 1)
grid_layout.addWidget(self.start_btn, 1, 2)
self.dump_procesor = DumpProcesor(self)
self.dump_procesor.process.setProgram("tcpdump")
filename = os.path.join(CURRENT_DIR, "packets.pcap")
self.dump_procesor.process.setArguments(["-i", "3", "-w", filename])
self.start_btn.clicked.connect(self.start)
self.dump_procesor.finished.connect(self.on_finished)
#QtCore.pyqtSlot()
def start(self):
self.log_te.clear()
self.start_btn.setDisabled(True)
self.dump_procesor.timer.setInterval(self.time_sb.value() * 1000)
self.dump_procesor.start()
#QtCore.pyqtSlot()
def on_finished(self):
self.start_btn.setDisabled(False)
filename = os.path.join(CURRENT_DIR, "packets.pcap")
packets = rdpcap(filename)
for packet in packets:
t = packet.show(dump=True)
self.log_te.append(t)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

python multiprocessing - sending child process logging to GUI running in parent

I'm building an interface on top of some analysis code I've written that executes some SQL and processes the query results. There's logging surrounding a number of the events in this analysis code that I would like to expose to the user. Because the analysis code is rather long-running, and because I don't want the UI to block, thus far I've done this through putting the analysis function in to its own thread.
Simplified example of what I have now (complete script):
import sys
import time
import logging
from PySide2 import QtCore, QtWidgets
def long_task():
logging.info('Starting long task')
time.sleep(3) # this would be replaced with a real task
logging.info('Long task complete')
class LogEmitter(QtCore.QObject):
sigLog = QtCore.Signal(str)
class LogHandler(logging.Handler):
def __init__(self):
super().__init__()
self.emitter = LogEmitter()
def emit(self, record):
msg = self.format(record)
self.emitter.sigLog.emit(msg)
class LogDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
log_txt = QtWidgets.QPlainTextEdit(self)
log_txt.setReadOnly(True)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(log_txt)
self.setWindowTitle('Event Log')
handler = LogHandler()
handler.emitter.sigLog.connect(log_txt.appendPlainText)
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.INFO)
class Worker(QtCore.QThread):
results = QtCore.Signal(object)
def __init__(self, func, *args, **kwargs):
super().__init__()
self.func = func
self.args = args
self.kwargs = kwargs
def run(self):
results = self.func(*self.args, **self.kwargs)
self.results.emit(results)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
widget = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(widget)
start_btn = QtWidgets.QPushButton('Start')
start_btn.clicked.connect(self.start)
layout.addWidget(start_btn)
self.setCentralWidget(widget)
self.log_dialog = LogDialog()
self.worker = None
def start(self):
if not self.worker:
self.log_dialog.show()
logging.info('Run Starting')
self.worker = Worker(long_task)
self.worker.results.connect(self.handle_result)
self.worker.start()
def handle_result(self, result=None):
logging.info('Result received')
self.worker = None
if __name__ == '__main__':
app = QtWidgets.QApplication()
win = MainWindow()
win.show()
sys.exit(app.exec_())
This works fine, except that I need to be able to allow the user to stop the execution of the analysis code. Everything I've read indicates that there is no way to interrupt threads nicely, so using the multiprocessing library seems to be the way to go (there's no way to re-write the analysis code to allow for periodic polling, since the majority of time is spent just waiting for the queries to return results). It's easy enough to get the same functionality in terms of executing the analysis code in a way that doesn't block the UI by using multiprocessing.Pool and apply_async.
E.g. replacing MainWindow from above with:
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
widget = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(widget)
start_btn = QtWidgets.QPushButton('Start')
start_btn.clicked.connect(self.start)
layout.addWidget(start_btn)
self.setCentralWidget(widget)
self.log_dialog = LogDialog()
self.pool = multiprocessing.Pool()
self.running = False
def start(self):
if not self.running:
self.log_dialog.show()
logging.info('Run Starting')
self.pool.apply_async(long_task, callback=self.handle_result)
def handle_result(self, result=None):
logging.info('Result received')
self.running = False
But I can't seem to figure out how I would go about retrieving the logging output from the child process and passing it to the parent to update the log dialog. I've read through just about every SO question on this as well as the cookbook examples of how to handle writing to a single log file from multiple processes, but I can't wrap my head around how to adapt those ideas to what I'm trying to do here.
Edit
So trying to figure out what might be going on for why I'm seeing different behavior than #eyllanesc I added:
logger = logging.getLogger()
print(f'In Func: {logger} at {id(logger)}')
and
logger = logging.getLogger()
print(f'In Main: {logger} at {id(logger)}')
to long_task and Mainwindow.start, respectively. When I run main.py I get:
In Main: <RootLogger root (INFO)> at 2716746681984
In Func: <RootLogger root (WARNING)> at 1918342302352
which seems to be what was described in this SO question
This idea of using a Queue and QueueHandler though as a solution seems similar to #eyllanesc's original solution
The signals do not transmit data between processes, so for this case a Pipe must be used and then emit the signal:
# other imports
import threading
# ...
class LogHandler(logging.Handler):
def __init__(self):
super().__init__()
self.r, self.w = multiprocessing.Pipe()
self.emitter = LogEmitter()
threading.Thread(target=self.listen, daemon=True).start()
def emit(self, record):
msg = self.format(record)
self.w.send(msg)
def listen(self):
while True:
try:
msg = self.r.recv()
self.emitter.sigLog.emit(msg)
except EOFError:
break
# ...
In case anyone wanders in to this down the road, using QueueHandler and QueueListener leads to a solution that works on Windows as well. Borrowed heavily from this answer to a similar question:
import logging
import sys
import time
import multiprocessing
from logging.handlers import QueueHandler, QueueListener
from PySide2 import QtWidgets, QtCore
def long_task():
logging.info('Starting long task')
time.sleep(3) # this would be replaced with a real task
logging.info('Long task complete')
def worker_init(q):
qh = QueueHandler(q)
logger = logging.getLogger()
logger.setLevel(logging.INFO)
logger.addHandler(qh)
class LogEmitter(QtCore.QObject):
sigLog = QtCore.Signal(str)
class LogHandler(logging.Handler):
def __init__(self):
super().__init__()
self.emitter = LogEmitter()
def emit(self, record):
msg = self.format(record)
self.emitter.sigLog.emit(msg)
class LogDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.log_txt = QtWidgets.QPlainTextEdit(self)
self.log_txt.setReadOnly(True)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.log_txt)
self.setWindowTitle('Event Log')
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
widget = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout(widget)
start_btn = QtWidgets.QPushButton('Start')
start_btn.clicked.connect(self.start)
layout.addWidget(start_btn)
self.setCentralWidget(widget)
self.log_dialog = LogDialog()
self.running = False
# sets up handler that will be used by QueueListener
# which will update the LogDialoag
handler = LogHandler()
handler.emitter.sigLog.connect(self.log_dialog.log_txt.appendPlainText)
self.q = multiprocessing.Queue()
self.ql = QueueListener(self.q, handler)
self.ql.start()
# main process should also log to a QueueHandler
self.main_log = logging.getLogger('main')
self.main_log.propagate = False
self.main_log.setLevel(logging.INFO)
self.main_log.addHandler(QueueHandler(self.q))
self.pool = multiprocessing.Pool(1, worker_init, [self.q])
def start(self):
if not self.running:
self.log_dialog.show()
self.main_log.info('Run Starting')
self.pool.apply_async(long_task, callback=self.handle_result)
def handle_result(self, result=None):
time.sleep(2)
self.main_log.info('Result received')
self.running = False
def closeEvent(self, _):
self.ql.stop()
if __name__ == '__main__':
app = QtWidgets.QApplication()
win = MainWindow()
win.show()
sys.exit(app.exec_())

Pyqt5 GUI Still Hangs When Using Thread

I'm new to python and pyqt.
I'm learning how to use threading with GUI.
I followed this tutorial
http://www.xyzlang.com/python/PyQT5/pyqt_multithreading.html
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import threading
from _ast import While
class Communicate(QObject):
signal = pyqtSignal(int, str)
class My_Gui(QWidget):
def __init__(self):
super().__init__()
self.comm = Communicate()
self.comm.signal.connect(self.append_data)
self.initUI()
def initUI(self):
btn_count = QPushButton('Count')
btn_count.clicked.connect(self.start_counting)
self.te = QTextEdit()
vbox = QVBoxLayout()
vbox.addWidget(btn_count)
vbox.addWidget(self.te)
self.setLayout(vbox)
self.setWindowTitle('MultiThreading in PyQT5')
self.setGeometry(400, 400, 400, 400)
self.show()
def count(self, comm):
'''
for i in range(10):
data = "Data "+str(i)
comm.signal.emit(i, data)
'''
i = 0
while True:
data = "Data "+str(i)
comm.signal.emit(i, data)
i+=1
def start_counting(self):
my_Thread = threading.Thread(target=self.count, args=(self.comm,))
my_Thread.start()
def append_data(self, num, data):
self.te.append(str(num) + " " + data)
if __name__ == '__main__':
app = QApplication(sys.argv)
my_gui = My_Gui()
sys.exit(app.exec_())
I changed the for loop to infinite while loop(incrementing the 'i').
If I execute the program, the GUI still hangs but if I remove the emit signal inside the loop, it no longer hangs.
Are there some tricks to make it not hangs?
while True makes an endless loop in the background
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
import threading
from _ast import While
class Communicate(QObject):
signal = pyqtSignal(int, str)
class My_Gui(QWidget):
def __init__(self):
super().__init__()
self.comm = Communicate()
self.comm.signal.connect(self.append_data)
self.initUI()
def initUI(self):
btn_count = QPushButton('Count')
btn_count.clicked.connect(self.start_counting)
self.te = QTextEdit()
vbox = QVBoxLayout()
vbox.addWidget(btn_count)
vbox.addWidget(self.te)
self.setLayout(vbox)
self.setWindowTitle('MultiThreading in PyQT5')
self.setGeometry(400, 400, 400, 400)
self.show()
def count(self, comm):
for i in range(10):
data = "Data "+str(i)
comm.signal.emit(i, data)
# While True below will never stop and cause your program to stuck
'''
i = 0
while True:
data = "Data "+str(i)
comm.signal.emit(i, data)
i+=1
'''
def start_counting(self):
my_Thread = threading.Thread(target=self.count, args=(self.comm,))
my_Thread.start()
def append_data(self, num, data):
self.te.append(str(num) + " " + data)
if __name__ == '__main__':
app = QApplication(sys.argv)
my_gui = My_Gui()
sys.exit(app.exec_())
I think you are getting downvoted for two things:
you did only copy and paste the code from the tutorial
you didn't read the tutorial
In the tutorial, the author states:
In the above example, we have created a QPushbutton and QTextEdit. When the button is clicked it creates a new Thread that counts from 0 to 9 and emits the signal in order to append the number and data in the QTextEdit. In class Communicate signal is initialized as pyqtSignal(int, str). This int and str means when a signal will be emitted it will also pass two arguments the first one will be of Integer type and second one will be of String type.
By changing the loop to while true you continuosly emit signals and append the text in the QTextEdit. Probably not what you want.
Also commenting the emit statement internally continues to run the while loop.

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