How to open content of a file in MDI subwindow from treeview - python

I have opened the file from the current directory in "opened" method, here file is opening and reading the data in it, but I want to write the read data in MDI subwindow.
from PyQt5 import QtWidgets
from PyQt5 import QtGui
from PyQt5 import QtCore
from PyQt5.QtWidgets import QMdiArea, QMdiSubWindow
from PyQt5.Qt import QMenu
import os
import tree2
class fileview(tree2.Ui_FOSApplication,QtWidgets.QMainWindow):
count = 0
def __init__(self):
super(fileview, self).__init__()
self.setupUi(self)
self.treeView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.treeView.customContextMenuRequested.connect(self.context_view)
self.populate()
def populate(self):
path = 'C:\FOS Application'
self.model = QtWidgets.QFileSystemModel()
self.model.setRootPath(QtCore.QDir.rootPath())
self.treeView.setModel(self.model)
self.treeView.setRootIndex(self.model.index(path))
#self.treeView.doubleClicked.connect(self.context_view)
#self.treeView.setSortingEnabled(True)
self.treeView.setColumnHidden(1, True)
self.treeView.setColumnHidden(2, True)
self.treeView.setColumnHidden(3, True)
def context_view(self):
view = QtWidgets.QMenu()
open = view.addAction("Open")
open.triggered.connect(self.subwindow)
curser = QtGui.QCursor()
view.exec_(curser.pos())
def subwindow(self):
fileview.count = fileview.count+1
self.w = self.openfile()
self.sub = QMdiSubWindow()
self.sub.setWidget(self.w)
#self.mdiArea.activeSubWindow(self.sub)
self.mdiArea.addSubWindow(self.sub)
self.sub.show()
def openfile(self):
index = self.treeView.currentIndex()
file_name = self.model.filePath(index)
os.startfile(file_name)
if __name__ == '__main__':
app = QtWidgets.QApplication([])`enter code here`
fb = fileview()
fb.show()
app.exec_()

Related

Get current value of another widget in a custom (promoted) widget in Qt Designer using PyQt5

I have created the ui for my application using Qt Designer. The UI includes two Widgets. A dropdown (ComboBox) with different values each representing a year (2015, 2025, 2035) and a custom widget that loads a shapefile on a map: Here is a screenshot of the UI (
Also, here is library.ui file) :
Here is my index.py file to connect to ui:
import sys
from os import environ
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.uic import loadUiType
ui,_=loadUiType('library.ui')
def suppress_qt_warnings():
environ["QT_DEVICE_PIXEL_RATIO"] = "0"
environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
environ["QT_SCREEN_SCALE_FACTORS"] = "1"
environ["QT_SCALE_FACTOR"] = "1"
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
def main():
suppress_qt_warnings()
app=QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
and here is the file associated with my custom widget (leafwidget.py):
import folium
import os.path
from PyQt5 import QtCore, QtWebEngineWidgets
from PyQt5.QtWidgets import *
import geopandas as gpd
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class LeafWidget (QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.view = QtWebEngineWidgets.QWebEngineView()
shp_filename = os.path.join(CURRENT_DIR, "input", '2015_loaded_NoCC.dbf')
shp_file = gpd.read_file(shp_filename)
shp_file_json_str = shp_file.to_json()
m = folium.Map(location=[39.764075, -86.159019], zoom_start=10)
folium.GeoJson(shp_file_json_str).add_to(m)
tmp_file = QtCore.QTemporaryFile("net.html", self)
if tmp_file.open():
m.save(tmp_file.fileName())
url = QtCore.QUrl.fromLocalFile(tmp_file.fileName())
self.view.load(url)
lay = QVBoxLayout(self)
lay.addWidget(self.view)
self.show()
As you can see in my custom widget Class (LeafWidget), the dbf file's name starts with the year value (2015, 2025, 2035) followed by "_loaded_NocCC.dbf" (for example "2015_loaded_NoCC.shp" and so on).
Now, I need to access the selected value from the dropdown list (let's say 2025) and then display the corresponding shapefile in the map (2025_loaded_NoCC.shp).
I can access the value of ComboBox easily using self.ComboBox.currentText() inside index.py, but in the leafletwidget class (leafwidget.py), I don't have access to self.ComboBox.currentText() and get the error that basically my Class has no attribute "ComboBox".
SO, how can I access the value of ComboBox in my LeafWidget class?
You have to create a method that updates the shapefile that will be shown, and call that method every time a new option is chosen generating the new path:
import folium
from PyQt5 import QtCore, QtWebEngineWidgets
from PyQt5.QtWidgets import *
import geopandas as gpd
class LeafWidget(QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
self.view = QtWebEngineWidgets.QWebEngineView()
lay = QVBoxLayout(self)
lay.addWidget(self.view)
self.tmp_file = QtCore.QTemporaryFile("XXXXXX.html")
def set_shapefile(self, filename):
shp_file = gpd.read_file(filename)
shp_file_json_str = shp_file.to_json()
m = folium.Map(location=[39.764075, -86.159019], zoom_start=10)
folium.GeoJson(shp_file_json_str).add_to(m)
if self.tmp_file.open():
m.save(self.tmp_file.fileName())
url = QtCore.QUrl.fromLocalFile(self.tmp_file.fileName())
self.view.load(url)
import sys
import os.path
from os import environ
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.uic import loadUiType
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
ui, _ = loadUiType(os.path.join(CURRENT_DIR, "library.ui"))
def suppress_qt_warnings():
environ["QT_DEVICE_PIXEL_RATIO"] = "0"
environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
environ["QT_SCREEN_SCALE_FACTORS"] = "1"
environ["QT_SCALE_FACTOR"] = "1"
class MainApp(QMainWindow, ui):
def __init__(self):
QMainWindow.__init__(self)
self.setupUi(self)
self.comboBox.currentTextChanged.connect(self.handle_currentTextChanged)
self.handle_currentTextChanged(self.comboBox.currentText())
def handle_currentTextChanged(self, text):
filename = shp_filename = os.path.join(
CURRENT_DIR, "input", "{}_loaded_NoCC.shp".format(text)
)
self.LeafWidget.set_shapefile(filename)
def main():
suppress_qt_warnings()
app = QApplication(sys.argv)
window = MainApp()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

PyQt5 drag and drop into system file explorer (with delayed encoding)?

I want to let users create files by dragging items from PyQt to the system file explorer. Since some of the files will be very large, I also need to delay setting the data to when the user finishes the drop instead of immediately on start of drag.
This example seems to be what I need: https://doc.qt.io/archives/4.6/draganddrop-delayedencoding.html
I tried converting that to a simple PyQt5 version where dragging a QPushButton into a folder will create a plain text file, but it's not working for me... when I run it dropping does nothing and my cursor looks like this:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
import typing
import time
class MimeData(QtCore.QMimeData):
dataRequested = QtCore.pyqtSignal(str)
def formats(self) -> typing.List[str]:
return QtCore.QMimeData.formats(self) + ["text/plain"]
def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
self.dataRequested.emit(mime_type)
return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)
class SourceWidget(QtWidgets.QWidget):
mimeData: MimeData = None
def __init__(self, parent=None):
super().__init__(parent)
layout = QtWidgets.QVBoxLayout()
button = QtWidgets.QPushButton("Drag Me")
button.pressed.connect(self.start_drag)
layout.addWidget(button)
self.setLayout(layout)
#QtCore.pyqtSlot()
def create_data(self, mime_type):
if mime_type == "text/plain":
time.sleep(0.25) # Simulate large file
self.mimeData.setData("text/plain", b"my text file contents")
#QtCore.pyqtSlot()
def start_drag(self):
self.mimeData = MimeData()
self.mimeData.dataRequested.connect(self.create_data)
drag = QtGui.QDrag(self)
drag.setMimeData(self.mimeData)
drag.exec(QtCore.Qt.CopyAction)
if __name__ == "__main__":
app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)
w = SourceWidget()
w.show()
app.exec_()
Here's what I ended up with for dragging and dropping files from PyQt5 into file explorer, and only having the file write once the mouse is released to finalize the drop.
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import tempfile
import os
# Use win32api on Windows because the pynput and mouse packages cause lag
# https://github.com/moses-palmer/pynput/issues/390
if os.name == 'nt':
import win32api
def mouse_pressed():
return win32api.GetKeyState(0x01) not in [0, 1]
else:
import mouse
def mouse_pressed():
return mouse.is_pressed()
class DelayedMimeData(QtCore.QMimeData):
def __init__(self):
super().__init__()
self.callbacks = []
def add_callback(self, callback):
self.callbacks.append(callback)
def retrieveData(self, mime_type: str, preferred_type: QtCore.QVariant.Type):
mp = mouse_pressed()
if not mp:
for callback in self.callbacks.copy():
self.callbacks.remove(callback)
callback()
return QtCore.QMimeData.retrieveData(self, mime_type, preferred_type)
class Navigator(QtWidgets.QTreeWidget):
def __init__(self):
super().__init__()
self.setHeaderLabels(["Name"])
QtWidgets.QTreeWidgetItem(self, ['Test1'])
QtWidgets.QTreeWidgetItem(self, ['Test2'])
QtWidgets.QTreeWidgetItem(self, ['Test3'])
self.setAcceptDrops(True)
self.setDragEnabled(True)
self.setDragDropMode(self.DragDrop)
self.setDefaultDropAction(Qt.MoveAction)
self.setSelectionMode(self.ExtendedSelection)
self.setSelectionBehavior(self.SelectRows)
self.setContextMenuPolicy(Qt.CustomContextMenu)
def startDrag(self, actions):
drag = QtGui.QDrag(self)
names = [item.text(0) for item in self.selectedItems()]
mime = DelayedMimeData()
path_list = []
for name in names:
path = os.path.join(tempfile.gettempdir(), 'DragTest', name + '.txt')
os.makedirs(os.path.dirname(path), exist_ok=True)
print(path)
def write_to_file(path=path, name=name, widget=self):
with open(path, 'w+') as f:
print("Writing large file(s)...")
time.sleep(2) # Sleep to simulate long file write
f.write(f"Contents of {name}")
mime.add_callback(write_to_file)
path_list.append(QtCore.QUrl.fromLocalFile(path))
mime.setUrls(path_list)
mime.setData('application/x-qabstractitemmodeldatalist',
self.mimeData(self.selectedItems()).data('application/x-qabstractitemmodeldatalist'))
drag.setMimeData(mime)
drag.exec_(Qt.MoveAction)
super().startDrag(actions)
app = QtWidgets.QApplication([])
nav = Navigator()
nav.show()
app.exec_()

Python pyqt5 Reminder and Notepad Launcher

I have met with a problem on Python. I tried to create a Reminder and Notepad.There is no troubles with Reminder, but the notepad is quite hard. I use QPlainTextEdit to open .txt files, save notes and so on.The problem is that it does not work. You may start looking from the class fileeki, cause notepad starts there. My interface is written in QTdesigner and the file's type is ui. I use mainwindow which is convertod to .py from .ui , but other widgets are as usual in .ui .Please help me!!!
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QRadioButton, QVBoxLayout, QStatusBar
from PyQt5.QtWidgets import QLabel, QPushButton, QMessageBox, QFileDialog, QPlainTextEdit
from PyQt5.QtGui import QPixmap
from ui_filebir import Ui_MainWindow
from win10toast import ToastNotifier
import time
import sqlite3
import easygui
from tkinter import filedialog
from tkinter import *
class MyWidget(QMainWindow,Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.resize(520, 300)
self.pushButton.clicked.connect(self.notepad_run)
self.re_but.clicked.connect(self.reminder_run)
self.pushButton_2.clicked.connect(self.dbrun)
self.rate = self.lineEdit.text()
def dbrun(self):
pass
#con = sql.connect('dbrate.db')
#cur = con.cursor()
#cur.execute(query)
#res = cur.execute(query)
#con.commit()
#con.close()
def notepad_run(self):
self.uineweki = fileeki()
self.uineweki.show()
self.close()
def reminder_run(self):
self.ui_fileush = fileush()
self.ui_fileush.show()
self.close()
class fileeki(QWidget):
def __init__(self, *args, **kwargs):
super().__init__()
uic.loadUi('uineweki.ui', self)
self.editor = QPlainTextEdit()
self.path = None
self.pushButton.clicked.connect(self.opening_run)
self.pushButton_2.clicked.connect(self.saving_run)
self.pushButton_3.clicked.connect(self.saveac)
self.pushButton_4.clicked.connect(self.bak)
def dialog_critical(self, s):
dlg = QMessageBox(self)
dlg.setText(s)
dlg.setIcon(QMessageBox.Critical)
dlg.show()
def opening_run(self):
path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Text documents (*.txt);All files (*.*)")
if path:
try:
with open(path, 'rU') as f:
text = f.read()
except Exception as e:
self.dialog_critical(str(e))
else:
self.path = path
self.editor.setPlainText(text)
def saving_run(self):
if self.path is None:
return self.saveac()
self._save_to_path(self.path)
def saveac(self):
path = QFileDialog.getSaveFileName(self, "Save file", "", "Text documents (*.txt);All files (*.*)")
if not path:
return
self._save_to_path(self.path)
def _save_to_path(self, path):
text = self.editor.toPlainText()
try:
with open(path, 'w') as f:
f.write(text)
except Exception as e:
self.dialog_critical(str(e))
else:
self.path = path
self.update_title()
def new_run(self):
pass
def bak(self):
self.close()
self.nazad = MyWidget()
self.nazad.show()
class fileush(QWidget):
def __init__(self, *args):
super().__init__()
uic.loadUi('ui_fileush.ui', self)
self.pushButton.clicked.connect(self.running)
self.pushButton_2.clicked.connect(self.bakk)
def running(self):
toaster = ToastNotifier()
self.first_input = self.lineEdit.text()
self.second_input = self.lineEdit_2.text()
t = time.sleep(int(self.first_input))
toaster.show_toast(self.second_input)
def bakk(self):
self.close()
self.nazad = MyWidget()
self.nazad.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = MyWidget()
ex.show()
sys.exit(app.exec())
my github https://github.com/iMAGA07/yandexProj
You are trying to set the text to the new QPlainTextEdit you created, but you should actually point it to the one you use in the gui:
def opening_run(self):
# ...
else:
self.path = path
# change this
# self.editor.setPlainText(text)
# to this
self.plainTextEdit.setPlainText(text)
That self.plainTextEdit is the object you created in designer (the object names are listed in the object inspector tree). Obviously, this also means that you don't need to create self.editor in the first place.

How to open other windows ui from the same class?

I need open other window (configuration windows) in my app.
Each window is a different class. I would like to know if I can group everything in the same class and open the window through a function.
from PyQt5 import QtWidgets, uic
import sys
class OpenMyApp(QtWidgets.QMainWindow):
# My App
pathUi = 'ui/interface.ui'
pathStylesheet = 'ui/stylesheet.qss'
def __init__(self):
super(OpenMyApp, self).__init__()
self.init_interface()
def init_interface(self):
self.ui = uic.loadUi(self.pathUi, self)
style_app = self.pathStylesheet
with open(style_app, "r") as fh:
self.setStyleSheet(fh.read())
self.ui.btn_openConfigApp.clicked.connect(self.open_config)
def open_config(self):
pass
class OpenMyConfigApp(QtWidgets.QMainWindow):
# My Config App
pathUi = 'ui/config-interface.ui'
pathStylesheet = 'ui/stylesheet.qss'
def __init__(self):
super(OpenMyConfigApp, self).__init__()
self.init_interface()
def init_interface(self):
self.ui = uic.loadUi(self.pathUi, self)
style_app = self.pathStylesheet
with open(style_app, "r") as fh:
self.setStyleSheet(fh.read())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = OpenMyApp()
window.show()
sys.exit(app.exec_())

Trouble updating QTableWidget

I have a running application that will take a CSV file and take out all the email addresses and display them on a QTableWidget. Unfortunately, it is only capable of doing this once. If I go back to select another CSV file the email TableWidget won't update, and the parameters will carry over to EmailList. This is also why I cannot init_ui in the constructer method of EmailList. I was wondering how the display can be updated, repeatedly with new file input. Here is an appropriate CSV file to run yourself. http://www.sharecsv.com/s/ed7c7a2154478339603a192921a352eb/csv_test.csv
email_list.py
import sys
import os
import re
import io
from construct import ConstructMessage
from PyQt5.QtWidgets import QFileDialog, QTableWidget,QTableWidgetItem, QVBoxLayout,QHBoxLayout, QWidget, QAction, QPushButton
from PyQt5.QtCore import Qt, pyqtSignal, QFileInfo, QDir
class EmailList(QWidget):
buttonClicked = pyqtSignal()
email_list = []
def __init__(self):
super().__init__()
print("Initzd")
#self.init_ui()
def init_ui(self):
self.v_layout = QVBoxLayout()
self.h_layout = QHBoxLayout()
self.email_widget = QTableWidget()
self.email_widget.setColumnCount(1)
for row_data in EmailList.email_list:
print("Email list: " + row_data)
row = self.email_widget.rowCount()
self.email_widget.insertRow(row)
for column, col in enumerate(row_data):
item = QTableWidgetItem(row_data)
self.email_widget.setItem(row, column, item)
width = 200
self.open_button = QPushButton("Open")
self.open_button.setMaximumWidth(width)
self.continue_button = QPushButton("Continue")
self.continue_button.setMaximumWidth(width)
self.back_button = QPushButton("Go back")
self.back_button.setMaximumWidth(width)
self.open_button.clicked.connect(lambda: self.open_click(self.open_button,"Open",self.widget))
self.continue_button.clicked.connect(lambda: self.continue_click(self.continue_button,"Continue"))
self.back_button.clicked.connect(lambda: self.on_back_clicked())
self.v_layout.addWidget(self.email_widget)
self.h_layout.addWidget(self.open_button)
self.h_layout.addWidget(self.continue_button)
self.h_layout.addWidget(self.back_button)
self.v_layout.addLayout(self.h_layout)
self.setLayout(self.v_layout)
self.setWindowTitle("Email List")
print("Welcome to the email_list widget")
self.show()
def on_back_clicked(self):
print("You are going back")
self.buttonClicked.emit()
def update_emails(self, imported_email_list):
EmailList.email_list = imported_email_list
def continue_click(self,continue_button,string):
pass
from sheet import Sheet
sheet.py
import sys
import os
import re
import io
import csv
from PyQt5.QtWidgets import QFileDialog, QTableWidget, QTableWidgetItem, QVBoxLayout,QHBoxLayout, QWidget, QAction, QPushButton
from PyQt5.QtCore import Qt, pyqtSignal, QFileInfo, QDir
class Sheet(QWidget):
buttonClicked = pyqtSignal()
email_list = []
def __init__(self,r,c):
super().__init__()
self.init_ui(r,c)
def init_ui(self,r,c):
self.v_layout = QVBoxLayout()
self.h_layout = QHBoxLayout()
self.sheet = QTableWidget()
self.sheet.setRowCount(r)
self.sheet.setColumnCount(c)
width = 200
self.open_button = QPushButton("Open")
self.open_button.setMaximumWidth(width)
self.continue_button = QPushButton("Continue")
self.continue_button.setMaximumWidth(width)
self.file_path = None
self.open_button.clicked.connect(lambda: self.open_click(self.open_button,"Open",self.sheet))
self.continue_button.clicked.connect(lambda: self.continue_click(self.continue_button,"Continue"))
self.v_layout.addWidget(self.sheet)
self.h_layout.addWidget(self.open_button)
self.h_layout.addWidget(self.continue_button)
self.v_layout.addLayout(self.h_layout)
self.setLayout(self.v_layout)
self.setWindowTitle("CSV Reader")
self.show()
def continue_click(self,continue_button,string):
self.buttonClicked.emit()
def open_click(self,open_button,string,sheet):
self.path = QFileDialog.getOpenFileName(self, 'Open CSV', os.getenv('HOME'), 'CSV(*.csv)')
if self.path[0] != '':
with open(self.path[0], 'rU') as csv_file:
self.sheet.setRowCount(0)
my_file = csv.reader(csv_file, delimiter=',', quotechar='|')
for row_data in my_file:
row = self.sheet.rowCount()
self.sheet.insertRow(row)
self.sheet.setColumnCount(len(row_data))
for column, col in enumerate(row_data):
item = QTableWidgetItem(col)
self.sheet.setItem(row, column, item)
self.file_path = self.path[0]
Sheet.email_list = re.findall(r'[\w_]+#[\w_]+\.[\w_]+', open(self.file_path).read())
EmailList.update_emails(self, Sheet.email_list)
from email_list import EmailList
and finally main.py
import sys
import os
import io
from sheet import Sheet
from email_list import EmailList
from PyQt5.QtWidgets import QApplication, QMainWindow, QStackedWidget
from PyQt5.QtCore import Qt
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.central_widget = QStackedWidget()
self.setCentralWidget(self.central_widget)
self.sheet_widget = Sheet(10,10)
self.email_list_widget = EmailList()
self.central_widget.addWidget(self.sheet_widget)
self.central_widget.addWidget(self.email_list_widget)
self.central_widget.setCurrentWidget(self.sheet_widget)
self.sheet_widget.buttonClicked.connect(lambda: self.central_widget.setCurrentWidget(self.email_list_widget))
self.sheet_widget.buttonClicked.connect(self.email_list_widget.init_ui)
self.email_list_widget.buttonClicked.connect(lambda: self.central_widget.setCurrentWidget(self.sheet_widget))
app = QApplication(sys.argv)
run = Main()
run.resize(500,500)
run.show()
sys.exit(app.exec_())
Any help or insight on seamlessly updating a UI from a widget across module would be super! I was thinking of a refresh method, but the email_list already gets updated. The UI should update by itself but it's not, and I am missing something.

Categories

Resources