update json external file in python dialog - python

Hello I am developing an application in python, my problem is that I am saving a json file and I am calling it in a QlistWidget inside a Dialog
[
{
"title":"El titulo",
"enabled":true,
"path":"path",
"id":"5"
},
{
"title":"El titulo 2",
"enabled":true,
"path":"path",
"id":"555"
},
{
"title":"El recontra titulo",
"enabled":false,
"path":"path",
"id":"5555"
},
{
"title":"El titulo",
"enabled":true,
"path":"path",
"id":"5"
}
]
Here I have the program running, I read the data correctly and I show them in a QlistWidget when I enter the dialog
GUI
the problem is when I update the json add more items, I close the dialog and return open but the list is not updated
here I leave my code
import sys
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, QLabel, QAction, QMessageBox
from PyQt5 import uic
from PyQt5.QtGui import QIcon
import modules.db as DB
#DB = DB.DB()
#DB.jsonOpen()
#class Dialogo Items
class Dialogo(QDialog):
def __init__(self, item):
QDialog.__init__(self)
uic.loadUi("menu/" + item + ".ui", self)
if item == 'addItems':
items = DB.jsonOpen('items')
for p in items:
self.listitems.addItem(p['title'])
self.listitems.repaint()
self.saveitem.clicked.connect(self.save_items)
self.cancelbtn.clicked.connect(self.close_dialog)
def save_items(self):
data = DB.jsonOpen('items')
title = self.title.text()
id = self.id.text()
if self.status.isChecked():
enabled = True
else: enabled = False
data.append({
'id': id,
'title': title,
'path': 'path',
'enabled': enabled
})
DB.jsonSave(data, 'items')
self.title.setText("")
self.id.setText("")
self.status.setChecked(False)
def close_dialog(self):
self.hide()
#class heredada de QMainWindow (consturctor de ventanas) principal
class ventana(QMainWindow):
#metodo constructor
def __init__(self):
#Iniciar el objeto QMainWindow
QMainWindow.__init__(self)
#cargar la configuracion de archivo .ui
uic.loadUi("app.ui", self)
#//// Barra de menu y acciones ////#
#Onjeto menuBar
menu = self.menuBar()
#Menu Padre Inicio
menu_inicio = menu.addMenu("&Inicio")
menu_inicio_items = QAction(QIcon("icons/add.png"), "&Agregar Items", self)
menu_inicio_items.setShortcut("Ctrl+i") #atajo de teclado
self.DialogoItems = Dialogo('addItems'); # instanciamos la clase Dialogo Items
menu_inicio_items.triggered.connect(self.OpenDialogItems) #lanzados el dialogo item desde el menu items
menu_inicio.addAction(menu_inicio_items)
#Menu Configuracon
menu_conf = menu.addMenu("&Configuración")
#configuracion general
menu_conf_general = QAction(QIcon("icons/setting.png"), "&General", self)
self.DialogConfGeneral = Dialogo('confGeneral')
menu_conf_general.triggered.connect(self.OpenDialogConfGeneral) # lanazmos la configuracion general
menu_conf.addAction(menu_conf_general)
#configuracion servidores
menu_conf_servers = QAction(QIcon("icons/earth.png"), "&Servidores", self)
menu_conf_servers.setShortcut("Ctrl+h")
self.DialogConfServer = Dialogo('confServers')
menu_conf_servers.triggered.connect(self.OpenDialogConfServers)
menu_conf.addAction(menu_conf_servers)
#Abrir dialog Agregar Items
def OpenDialogItems(self):
self.DialogoItems.exec_()
#Abrir dialog Configuracion general
def OpenDialogConfGeneral(self):
self.DialogConfGeneral.exec_()
#Abrir dialog Configuracion Servidores
def OpenDialogConfServers(self):
self.DialogConfServer.exec_()
#instancia para iniciar una aplicacion
app = QApplication(sys.argv)
#app.setQuitOnLastWindowClosed(False)
#crear un objeto de la clase ventana
_ventana = ventana()
#mostrar ventana
_ventana.show()
app.exec_()
the save and read function works perfectly, the code of both
import os
import json
def jsonSave(data, file):
with open("data/"+file+".json", "w") as outfile:
json.dump(data, outfile)
def jsonOpen(file):
if os.path.exists('data/'+file+'.json') == True:
with open("data/"+file+".json", 'r') as json_file:
data = json.load(json_file)
else:
data = {}
data = []
return data
I'm using
- python 3
-pyQt5

The problem is caused by the fact that the data load is only given in the constructor, once the data is not updated since a new recharge is not done, what must be done is to create a method that the QListWidget must Reload whenever necessary or add the new item directly to the QListWidget, given the above, I have implemented the following code:
class Dialogo(QDialog):
def __init__(self, item):
QDialog.__init__(self)
uic.loadUi("menu/" + item + ".ui", self)
if item == 'addItems':
self.load()
self.saveitem.clicked.connect(self.save_items)
self.cancelbtn.clicked.connect(self.reject)
def load(self):
self.listitems.clear()
items = DB.jsonOpen('items')
for p in items:
self.listitems.addItem(p['title'])
def save_items(self):
data = DB.jsonOpen('items')
title = self.title.text()
id = self.id.text()
enabled = self.status.isChecked():
data.append({
'id': id,
'title': title,
'path': 'path',
'enabled': enabled
})
DB.jsonSave(data, 'items')
self.title.clear()
self.id.clear()
self.status.setChecked(False)
self.listitems.addItem(title)
# self.load()
I also recommend that if the data is going to be large it is not appropriate to save it in a json since it will see a great latency in the reading and writing of the data, the appropriate thing for those cases is to use a database, for example to use sqlite.

Related

Add dynamically widget in a loop, and get its name, pyQt5

I want to add a widget in a formLayout with a loop.
In an other function, I want to be able to interact with those widgets, that I have just created.
I tried with a dictionnary. But I have this error: dlg.pushb_freflechis.clicked.connect(recup_fichiers_selec)
NameError: name 'recup_fichiers_selec' is not defined
from PyQt5.QtWidgets import QApplication, QWidget, QComboBox, QCheckBox
from PyQt5 import uic
import sys
import glob, os
import sys
import webbrowser
from pathlib import Path
app = QApplication(sys.argv) # création application
dlg = uic.loadUi("logiciel_Rint3.ui") # charge l'IHM crée avec Qt Designer
def charger_fichiers():
# nom_cristal = dlg.lineEdit_cristal.text()
# date = dlg.lineEdit_date.text()
nom_cristal = "SiTrans"
date = "2022-05-06"
directory = 'C:/Users/diops/Desktop/Programme Rint_numérique/dépouillement/'+nom_cristal+'/'+date+'/'+'direct'
os.chdir(directory)
# webbrowser.open(directory)
global L_file_direct
L_file_direct = []
# L_checkb_direct = []
# input("Enregistrez les fichiers des signaux directs")
global c_d, var_checkd
c_d=1
var_checkd = dict()
for file in glob.glob("*.tif"):
globals()[f"checkb_direct{c_d}"] = QCheckBox()
var_checkd[c_d] = globals()[f"checkb_direct{c_d}"]
dlg.formLayout_direct.addRow(Path(file).stem, globals()[f"checkb_direct{c_d}"])
L_file_direct.append(Path(file).stem)
c_d += 1
directory = 'C:/Users/diops/Desktop/Programme Rint_numérique/dépouillement/'+nom_cristal+'/'+date+'/'+'reflechi'
os.chdir(directory)
# webbrowser.open(directory)
# L_checkb_reflechi = []
global L_file_reflechi
L_file_reflechi = []
# input("Enregistrez les fichiers des signaux réflechis")
global c_r,var_checkr
var_checkr = dict()
c_r=1
for file in glob.glob("*.tif"):
globals()[f"checkb_reflechi{c_r}"] = QCheckBox()
var_checkr[c_r] = globals()[f"checkb_reflechi{c_r}"]
dlg.formLayout_reflechi.addRow(Path(file).stem, globals()[f"checkb_reflechi{c_r}"])
L_file_reflechi.append(Path(file).stem)
c_r += 1
for i in range (1,c_d):
checkb = var_checkd[i]
if dlg.checkb.isTristate():
print(dlg.L_file_direct[i].text())
for i in range (1,c_r):
checkb = var_checkr[i]
if dlg.checkb.isTristate():
print(dlg.L_file_reflechi[i].text())
return
def recup_fichiers_selec():
for i in range (1,c_d):
checkb = var_checkd[i]
if dlg.checkb.isTristate():
print(dlg.L_file_direct[i].text())
for i in range (1,c_r):
checkb = var_checkr[i]
if dlg.checkb.isTristate():
print(dlg.L_file_reflechi[i].text())
return
dlg.pushb_ini.clicked.connect(charger_fichiers)
dlg.pushb_freflechis.clicked.connect(recup_fichiers_selec)
# Execution
dlg.show()
app.exec()
your code is so messy 😉 i can not understand it much! but if you want to create widgets and save them in a dictionary a simple example in pyqt (not ui) is like this which you add objects to dictionary:
keys = dict()
for i in range(1, 7):
keys[i] = QtWidgets.QPushButton(f'key_{i}')
keys[i].clicked.connect(func)
and also if you want to get all variables inside class you can use local which i dont recommend it in some cases.
for key, value in vars(self).items():
self.dictionary[key] = value
and maybe it is better to write your code using class and it is not really a good practice to use global variables!

How can I filter an ms-access databse, using QSqlTableModel and QLineEdit?

I'm building a GUI that allows users to search information in a ms access database
(yup. It has to be the ms access)
The user has a textfield where he can type his search
and the Tableview should update instantly.
At the moment the DB disappears whenever you type a letter in the field.
Took me a while to figure out the problem: my SQL statement is simply not right.
(Thanks to model.lastError)
The whole function looks like this:
self.ui.Kistenschild_suchen.textChanged.connect(self.update_filter)
def update_filter(self, s):
s = re.sub("[\W_]+", "", s)
filter_str = 'Produkt LIKE %{}%"'.format(s)
self.ui.model.setFilter(filter_str)
print(self.ui.model.lastError())
In this case I typed k
The errormessage is:
PySide6.QtSql.QSqlError("-3100", "QODBC: Unable to execute statement", "[Microsoft][ODBC-Treiber für Microsoft Access] Syntaxfehler in Abfrageausdruck 'Produkt LIKE (%h%\")'.") at 0x000001CA4FB33B88>
Point of interest should be the
'%h%")'."'
Since it shows more characters than typed
I tried to change in several ways, like changing the % to * and?
Still nothing
EDIT:
Here is the minimal reproducible example:
import re
import sys
from PySide6.QtCore import QSize, Qt
from PySide6.QtSql import QSqlDatabase, QSqlTableModel
from PySide6.QtWidgets import (
QApplication,
QLineEdit,
QMainWindow,
QTableView,
QVBoxLayout,
QWidget,
)
Driver= r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=D:\scripts\python\pyside_Tutorials\databases\chinook.accdb'
db = QSqlDatabase("QODBC")
db.setDatabaseName(Driver)
db.open()
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
container = QWidget()
layout = QVBoxLayout()
self.search = QLineEdit()
self.search.textChanged.connect(self.update_filter)
self.table = QTableView()
layout.addWidget(self.search)
layout.addWidget(self.table)
container.setLayout(layout)
self.model = QSqlTableModel(db=db)
self.table.setModel(self.model)
self.model.setTable("Track")
self.model.select()
self.setMinimumSize(QSize(1024, 600))
self.setCentralWidget(container)
# tag::filter[]
def update_filter(self, s):
s = re.sub("[\W_]+", "", s)
filter_str = 'Name LIKE "%{}%"'.format(s)
self.model.setFilter(filter_str)
print(self.model.lastError())
print(s,type(s))
# end::filter[]
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
This code gives me the errormessage:
<PySide6.QtSql.QSqlError("-3010", "QODBC: Unable to execute statement", "[Microsoft][ODBC-Treiber für Microsoft Access] 1 Parameter wurden erwartet, aber es wurden zu wenig Parameter übergeben.") at 0x0000016FC7535108>
Which means something like: "1 parameter was expected but too few parameters were passed"
MS-Access needs a double apostrophe like:
def update_filter(self, s):
s = re.sub(r"[\W_]+", "", s)
filter_str = f"Produkt '%{s}%'"
self.model.setFilter(filter_str)```

Add a large shapefile to map in python using folium

I am displaying a folium map in my application using python, PyQt5 and Qt designer. Since there is no map widget in Qt designer, I add a general widget and then promote it to my custom map widget. It all works fine. Here is the python code for my promoted widget:
import io
import folium
from PyQt5 import QtWebEngineWidgets
from PyQt5.QtWidgets import *
class LeafWidget (QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
m = folium.Map(
location=[40, -120] , zoom_start=10
)
self.view = QtWebEngineWidgets.QWebEngineView()
data = io.BytesIO()
m.save(data, close_file=False)
self.view.setHtml(data.getvalue().decode())
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.view)
self.show()
This works fine and I can see the map in my application.
I am also trying to display a GIS shapefile on top of this map. I have done some research and it seems like I cannot add GIS shapefile (.shp) directly to a folium map. So, I try to convert it to json first and then add the json on top of the map. I modified my code as below to add the .shp file to map:
import io
import folium
import os.path
from PyQt5 import QtWebEngineWidgets
from PyQt5.QtWidgets import *
import geopandas as gpd
class LeafWidget (QWidget):
def __init__(self, parent=None):
QWidget.__init__(self, parent)
m = folium.Map(
location=[40, -120] , zoom_start=10
)
self.view = QtWebEngineWidgets.QWebEngineView()
# converting shp to geojson
shp_file = gpd.read_file('input/2015_loaded_NoCC.shp')
shp_file.to_file('myshpfile.json', driver='GeoJSON')
shp = os.path.join('', 'myshpfile.json')
data = io.BytesIO()
folium.GeoJson(shp).add_to(m)
m.save(data, close_file=False)
self.view.setHtml(data.getvalue().decode())
self.layout = QVBoxLayout(self)
self.layout.addWidget(self.view)
self.show()
but now my map doesn't show up at all. It's just an empty space with no errors in the console or error log. If I save the map as an HTML file using "m.save('map.html')" though, it does save the file and when I open it, it displays the json file on the map, but for some reason, the way I am doing it to show the map in my application is not working after adding the shp-->json file. What am I doing wrong?
As already pointed out in these questions(1 and 2) and in the official docs:
void QWebEnginePage::setHtml(const QString &html, const QUrl &baseUrl
= QUrl()) Sets the content of this page to html. baseUrl is optional and used to resolve relative URLs in the document, such as referenced
images or stylesheets.
The html is loaded immediately; external objects are loaded
asynchronously.
If a script in the html runs longer than the default script timeout
(currently 10 seconds), for example due to being blocked by a modal
JavaScript alert dialog, this method will return as soon as possible
after the timeout and any subsequent html will be loaded
asynchronously.
When using this method, the web engine assumes that external
resources, such as JavaScript programs or style sheets, are encoded in
UTF-8 unless otherwise specified. For example, the encoding of an
external script can be specified through the charset attribute of the
HTML script tag. It is also possible for the encoding to be specified
by the web server.
This is a convenience function equivalent to setContent(html,
"text/html", baseUrl).
Note: This method will not affect session or global history for the
page.
Warning: This function works only for HTML, for other mime types (such
as XHTML and SVG) setContent() should be used instead.
Warning: The content will be percent encoded before being sent to the
renderer via IPC. This may increase its size. The maximum size of the
percent encoded content is 2 megabytes minus 30 bytes.
(emphasis mine)
setHtml() does not support content greater than 2MB, so in your particular case there are 2 solutions:
Save the folium map in an html file:
import io
import os
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class LeafWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.view = QtWebEngineWidgets.QWebEngineView()
shp_filename = os.path.join(CURRENT_DIR, "input", "2015_loaded_NoCC.shp")
shp_file = gpd.read_file(shp_filename)
shp_file_json_str = shp_file.to_json()
m = folium.Map(location=[40, -120], zoom_start=10)
folium.GeoJson(shp_file_json_str).add_to(m)
tmp_file = QtCore.QTemporaryFile("XXXXXX.html", self)
if tmp_file.open():
m.save(tmp_file.fileName())
url = QtCore.QUrl.fromLocalFile(tmp_file.fileName())
self.view.load(url)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.view)
def main():
app = QtWidgets.QApplication([])
w = LeafWidget()
w.show()
app.exec_()
if __name__ == "__main__":
main()
Use a QWebEngineUrlSchemeHandler to return the html:
qfolium.py
import json
import io
from PyQt5 import QtCore, QtWebEngineCore, QtWebEngineWidgets
class FoliumSchemeHandler(QtWebEngineCore.QWebEngineUrlSchemeHandler):
def __init__(self, app):
super().__init__(app)
self.m_app = app
def requestStarted(self, request):
url = request.requestUrl()
name = url.host()
m = self.m_app.process(name, url.query())
if m is None:
request.fail(QtWebEngineCore.QWebEngineUrlRequestJob.UrlNotFound)
return
data = io.BytesIO()
m.save(data, close_file=False)
raw_html = data.getvalue()
buf = QtCore.QBuffer(parent=self)
request.destroyed.connect(buf.deleteLater)
buf.open(QtCore.QIODevice.WriteOnly)
buf.write(raw_html)
buf.seek(0)
buf.close()
request.reply(b"text/html", buf)
class FoliumApplication(QtCore.QObject):
scheme = b"folium"
def __init__(self, parent=None):
super().__init__(parent)
scheme = QtWebEngineCore.QWebEngineUrlScheme(self.scheme)
QtWebEngineCore.QWebEngineUrlScheme.registerScheme(scheme)
self.m_functions = dict()
def init_handler(self, profile=None):
if profile is None:
profile = QtWebEngineWidgets.QWebEngineProfile.defaultProfile()
handler = profile.urlSchemeHandler(self.scheme)
if handler is not None:
profile.removeUrlSchemeHandler(handler)
self.m_handler = FoliumSchemeHandler(self)
profile.installUrlSchemeHandler(self.scheme, self.m_handler)
def register(self, name):
def decorator(f):
self.m_functions[name] = f
return f
return decorator
def process(self, name, query):
f = self.m_functions.get(name)
if f is None:
print("not found")
return
items = QtCore.QUrlQuery(query).queryItems()
params_json = dict(items).get("json", None)
if params_json is not None:
return f(**json.loads(params_json))
return f()
def create_url(self, name, params=None):
url = QtCore.QUrl()
url.setScheme(self.scheme.decode())
url.setHost(name)
if params is not None:
params_json = json.dumps(params)
query = QtCore.QUrlQuery()
query.addQueryItem("json", params_json)
url.setQuery(query)
return url
main.py
import io
import os
import folium
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
import geopandas as gpd
from qfolium import FoliumApplication
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
folium_app = FoliumApplication()
#folium_app.register("load_shapefile")
def load_shapefile(latitude, longitude, zoom_start, shp_filename):
shp_file = gpd.read_file(shp_filename)
shp_file_json_str = shp_file.to_json()
m = folium.Map(
location=[latitude, longitude], zoom_start=zoom_start
)
folium.GeoJson(shp_file_json_str).add_to(m)
print(m)
return m
class LeafWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
QtWidgets.QWidget.__init__(self, parent)
self.view = QtWebEngineWidgets.QWebEngineView()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.view)
self.resize(640, 480)
shp_filename = os.path.join(CURRENT_DIR, "input", "2015_loaded_NoCC.shp")
params = {
"shp_filename": shp_filename,
"latitude": 40,
"longitude": -120,
"zoom_start": 5,
}
url = folium_app.create_url("load_shapefile", params=params)
self.view.load(url)
def main():
app = QtWidgets.QApplication([])
folium_app.init_handler()
w = LeafWidget()
w.show()
app.exec_()
if __name__ == "__main__":
main()

Why function defined in class is not visible in other fragments of code?

I am playing with python, being completely new at that. I wrote my first "serious" piece of code using tkinter and beautifulsoup and stuff and it worked. Now, trying to expand my knowledge I am re-writing it using pyqt5 and trying to use classes instead of "spaghetti" code.
My program in general works, it reads website, parses the html code with BeautifulSoup, gets required lines, etc. I used some "calculator" tutorial to base it on and with many trials and errors I made it work. Code below:
from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QVBoxLayout, QPushButton, QFileDialog, QMainWindow
from PyQt5.QtCore import Qt, QDate, QTimer, QEventLoop
from PyQt5.QtGui import QIcon, QPixmap
import sys
import os
import requests
from bs4 import BeautifulSoup
from operator import itemgetter
ERROR_MSG = 'ERROR'
class BinColUI(QMainWindow):
def createLabelTop(self):
self.label_top = QLabel('PLEASE WAIT')
self.label_top.setAlignment(Qt.AlignCenter)
self.label_top.setStyleSheet("font: 14pt Bahnschrift; color: yellow")
self.generalLayout.addWidget(self.label_top, alignment=Qt.AlignCenter)
def createLabelBot(self):
self.label_bot = QLabel('PLEASE WAIT')
self.label_bot.setAlignment(Qt.AlignCenter)
self.label_bot.setStyleSheet("font: 14pt Bahnschrift; color: yellow")
self.generalLayout.addWidget(self.label_bot, alignment=Qt.AlignCenter)
def setLabels(self, texttop, textbot):
self.label_top.setText(texttop)
self.label_bot.setText(textbot)
def createLabelImg(self):
label_img = QLabel()
label_img.setFixedSize(self.window().width(), 300)
label_img.setAlignment(Qt.AlignCenter)
image = 'img\pleasewait'
pixmap = QPixmap(resource_path(image+'.png'))
pixmap = pixmap.scaledToHeight(label_img.height(), Qt.SmoothTransformation)
label_img.setPixmap(pixmap)
self.generalLayout.addWidget(label_img, alignment=Qt.AlignCenter)
def setLabelImg(self, bin_color):
image = 'img\'+bin_color'
pixmap = QPixmap(resource_path(image + '.png'))
pixmap = pixmap.scaledToHeight(self.label_img.height(), Qt.SmoothTransformation)
self.label_img.setPixmap(pixmap)
def __init__(self):
super().__init__()
self.setWindowTitle('Bin Collection')
self.setFixedSize(500, 500)
self.setStyleSheet('background-color: #7C7D7B')
self.generalLayout = QVBoxLayout()
self._centralWidget = QWidget(self)
self.setCentralWidget(self._centralWidget)
self._centralWidget.setLayout(self.generalLayout)
self.createLabelTop()
self.createLabelImg()
self.createLabelBot()
class BinColCtrl:
def __init__(self, model, view):
self._evaluate = model
self._view = view
self.calculateResult()
def calculateResult(self):
line_top = parseGoodLines(0)
line_bottom = parseGoodLines(1)
self._view.setLabels(line_top, line_bottom)
self._view.
'''
Why the function setLabelImg from class BinColUi is not visible here?
I can call setLabel (as shown above) but no setLabelImg.
'''
def parseGoodLines(linia_number):
global bin_color
try:
if linia_number==0:
start_text='Your next collection is '
else:
start_text='After that: '
kosz_name = good_lines[linia_number][0]
kosz_date = good_lines[linia_number][1]
kosz_date_str = QDate.toString(kosz_date, 'dd MMMM yyyy')
ile_dni=QDate.currentDate().daysTo(kosz_date)
result = '%s%s\nYou need to put it outside before %s\nIt\'s in %s days' \
%(start_text, str.upper(kosz_name), kosz_date_str, str(ile_dni))
except Exception:
result = ERROR_MSG
return result
def resource_path(relative_path):
base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
class MakeSoup:
def getDataFromWebsite(self):
URL = 'http://mydurham.durham.gov.uk/article/12690?uprn=100110375827'
page = requests.get(URL)
soup = BeautifulSoup(page.content, 'html.parser')
results = soup.find(id='page_PageContentHolder_template_pnlArticleBody')
return results
def mixSoup(self, dane):
linie_ze_strony = dane.find_all('p')
global good_lines
good_lines=[]
for kosz in linie_ze_strony:
linia_bez_p = str(kosz).replace('<p>', "")
linia_bez_p = str(linia_bez_p).replace('</p>', "")
kosz = linia_bez_p
if 'Your next ' in str(kosz):
if 'rubbish' in str(kosz):
rubbish_len = len(str(kosz)) - 1
date_rubbish = str(kosz)[33:rubbish_len]
if 'recycling' in str(kosz):
recycle_len = len(str(kosz)) - 1
date_recycle = str(kosz)[35:recycle_len]
qdate_rubbish = QDate.fromString(date_rubbish, 'dd MMMM yyyy')
qdate_recycle = QDate.fromString(date_recycle, 'dd MMMM yyyy')
good_lines.append(['Rubbish', qdate_rubbish])
good_lines.append(['Recycling', qdate_recycle])
good_lines.sort(key=itemgetter(1))
return good_lines
def __init__(self):
self.mixSoup(self.getDataFromWebsite())
def main():
bincol = QApplication(sys.argv)
view = BinColUI()
view.show()
MakeSoup()
model = parseGoodLines
BinColCtrl(model=model, view=view)
sys.exit(bincol.exec_())
if __name__ == '__main__':
main()
In class BinColUi I have some functions which I'm using later on to build and change some visual elements. In class BinColCtrl I change text on the labels using function setLabels form BinColUi class and it works alright. But when I try to call function setLabelImg from the same class it's not visible (see attaached pic) and I can't figure why. In fact only function setLabels is available.
Your IDE does not know the type of self._view. It only knows that self._view has a setLabels attribute because you just used that.
Annotate the variable with the correct type and your IDE can discover the method.
class BinColCtrl:
# ``: BinColUI`` tells the IDE the type of ``view`` and ``self._view``
def __init__(self, model, view: BinColUI):
self._evaluate = model
self._view = view
self.calculateResult()
It seems that your IDE doesn't know type of self._view object. It sees setLabels because it was used in the line above.
Try adding type annotation like following:
class BinColCtrl:
def __init__(self, model, view):
self._evaluate = model
self._view: BinColUi = view # <-- this type annotation might help
self.calculateResult()
You can find more about type annotations here

Threading in pyqt4

In my GUI I have to download lots of stuff in between. I use urllib to do that. the problem of course then becomes that the GUI freezes up until everything gets downloaded.
My code is something like following
QtCore.QObject.connect( self.UI.commandLinkButton_2 , QtCore.SIGNAL("clicked()") , self.addStoryToHistory )
wherein the above function has the downloading code.
There is nothing like sending of shared data among this and the process just involves downloading of the data to a location.
What is the simplest way to not freeze up my GUI ? Should i use multiprocessing or QThreads?
Can anybody point me to some links.... I do not wish it to be very complex so if there is any easier way do it please point it out....
Thanks a lot...
Here's an example I've just stripped from a project I was working on a couple of months back using the http example from PyQt as a base. It'll download SIP from the Riverbank website.
It's using QHttp from QtNetwork instead of urllib and the progress bar is connected to its dataReadProgress signal. This should allow you to reliably download a file as well as having a responsive GUI.
from PyQt4.QtCore import QUrl, QFileInfo, QFile, QIODevice
from PyQt4.QtGui import QApplication, QDialog, QProgressBar, QLabel, QPushButton, QDialogButtonBox, \
QVBoxLayout, QMessageBox
from PyQt4.QtNetwork import QHttp
url_to_download = 'http://www.riverbankcomputing.co.uk/static/Downloads/sip4/sip-4.12.3.zip'
class Downloader(QDialog):
def __init__(self, parent=None):
super(Downloader, self).__init__(parent)
self.httpGetId = 0
self.httpRequestAborted = False
self.statusLabel = QLabel('Downloading %s' % url_to_download)
self.closeButton = QPushButton("Close")
self.closeButton.setAutoDefault(False)
self.progressBar = QProgressBar()
buttonBox = QDialogButtonBox()
buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole)
self.http = QHttp(self)
self.http.requestFinished.connect(self.httpRequestFinished)
self.http.dataReadProgress.connect(self.updateDataReadProgress)
self.http.responseHeaderReceived.connect(self.readResponseHeader)
self.closeButton.clicked.connect(self.cancelDownload)
mainLayout = QVBoxLayout()
mainLayout.addWidget(self.statusLabel)
mainLayout.addWidget(self.progressBar)
mainLayout.addWidget(buttonBox)
self.setLayout(mainLayout)
self.setWindowTitle('Download Example')
self.downloadFile()
def downloadFile(self):
url = QUrl(url_to_download)
fileInfo = QFileInfo(url.path())
fileName = fileInfo.fileName()
if QFile.exists(fileName):
QFile.remove(fileName)
self.outFile = QFile(fileName)
if not self.outFile.open(QIODevice.WriteOnly):
QMessageBox.information(self, 'Error',
'Unable to save the file %s: %s.' % (fileName, self.outFile.errorString()))
self.outFile = None
return
mode = QHttp.ConnectionModeHttp
port = url.port()
if port == -1:
port = 0
self.http.setHost(url.host(), mode, port)
self.httpRequestAborted = False
path = QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:#/")
if path:
path = str(path)
else:
path = '/'
# Download the file.
self.httpGetId = self.http.get(path, self.outFile)
def cancelDownload(self):
self.statusLabel.setText("Download canceled.")
self.httpRequestAborted = True
self.http.abort()
self.close()
def httpRequestFinished(self, requestId, error):
if requestId != self.httpGetId:
return
if self.httpRequestAborted:
if self.outFile is not None:
self.outFile.close()
self.outFile.remove()
self.outFile = None
return
self.outFile.close()
if error:
self.outFile.remove()
QMessageBox.information(self, 'Error',
'Download failed: %s.' % self.http.errorString())
self.statusLabel.setText('Done')
def readResponseHeader(self, responseHeader):
# Check for genuine error conditions.
if responseHeader.statusCode() not in (200, 300, 301, 302, 303, 307):
QMessageBox.information(self, 'Error',
'Download failed: %s.' % responseHeader.reasonPhrase())
self.httpRequestAborted = True
self.http.abort()
def updateDataReadProgress(self, bytesRead, totalBytes):
if self.httpRequestAborted:
return
self.progressBar.setMaximum(totalBytes)
self.progressBar.setValue(bytesRead)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
downloader = Downloader()
downloader.show()
sys.exit(app.exec_())
I suggest you to use the QNetworkManager instead and monitor the download process.
See this other question:
pyQT QNetworkManager and ProgressBars

Categories