Having QCheckBox wants to save and restore checkstate after closing file.
Tried following but it does not really work!
The code:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class SecondOrder(QtWidgets.QWidget):
def __init__(self, parent=None):
super(SecondOrder, self).__init__(parent)
self.setFont(QtGui.QFont("Helvetica", 8, QtGui.QFont.Normal, italic=False))
curvaturelabel = QtWidgets.QLabel('Nominal curvature')
stiffnesslabel = QtWidgets.QLabel('Nominal stiffness')
simcurvaturelabel = QtWidgets.QLabel('Simplified nominal curvature')
self.curvaturecheck = QtWidgets.QCheckBox()
self.stiffnesscheck = QtWidgets.QCheckBox()
self.simcurvaturecheck = QtWidgets.QCheckBox()
self.clay = QtWidgets.QVBoxLayout()
self.clay.addWidget(curvaturelabel)
self.clay.addWidget(stiffnesslabel)
self.clay.addWidget(simcurvaturelabel)
self.dlay = QtWidgets.QVBoxLayout()
self.dlay.addWidget(self.curvaturecheck)
self.dlay.addWidget(self.stiffnesscheck)
self.dlay.addWidget(self.simcurvaturecheck)
grid = QtWidgets.QGridLayout(self)
grid.addLayout(self.dlay, 0, 0)
grid.addLayout(self.clay, 0, 1)
Secondorder_Group = QtWidgets.QGroupBox(self)
Secondorder_Group.setTitle("&Second order analysis method")
Secondorder_Group.setLayout(grid)
self.elay = QtWidgets.QHBoxLayout(self)
self.elay.addWidget(Secondorder_Group)
self.elay.setSizeConstraint(self.elay.SetFixedSize)
group = QtWidgets.QButtonGroup(self)
group.addButton(self.curvaturecheck)
group.addButton(self.stiffnesscheck)
group.addButton(self.simcurvaturecheck)
self.readSettings()
self.curvaturecheck.stateChanged.connect(lambda: self.writeSettings())
self.stiffnesscheck.stateChanged.connect(lambda: self.writeSettings())
self.simcurvaturecheck.stateChanged.connect(lambda: self.writeSettings())
def readSettings(self):
settings = QtCore.QSettings('file.ini')
settings.beginGroup("QCheckBox")
self.curvaturecheck.setCheckState(settings.value("A", QtCore.Qt.Checked, bool))
self.stiffnesscheck.setCheckState(settings.value("B", False, bool))
self.simcurvaturecheck.setCheckState(settings.value("C", False, bool))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings('file.ini')
settings.beginGroup("QCheckBox")
settings.setValue("A", self.curvaturecheck.isCheckable())
settings.setValue("B", self.stiffnesscheck.isCheckable())
settings.setValue("C", self.simcurvaturecheck.isCheckable())
settings.endGroup()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = SecondOrder()
w.show()
sys.exit(app.exec_())
Note that following codes are tried, it really saves and restores but it mix multiple checks? wants to be able to check once and restore.
settings.setValue("A", self.curvaturecheck.isChecked())
settings.setValue("B", self.stiffnesscheck.isChecked())
settings.setValue("C", self.simcurvaturecheck.isChecked())
If you are going to save a type T data then you must use the function that uses type T, in your case you save a boolean with isChecked() and you want to use the function setCheckState() that uses a Qt::CheckState type causing the error.
Considering the above there are 2 solutions:
Use bool:
def readSettings(self):
settings = QtCore.QSettings("file.ini")
settings.beginGroup("QCheckBox")
self.curvaturecheck.setChecked(settings.value("A", True, bool))
self.stiffnesscheck.setChecked(settings.value("B", False, bool))
self.simcurvaturecheck.setChecked(settings.value("C", False, bool))
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings("file.ini")
settings.beginGroup("QCheckBox")
settings.setValue("A", self.curvaturecheck.isChecked())
settings.setValue("B", self.stiffnesscheck.isChecked())
settings.setValue("C", self.simcurvaturecheck.isChecked())
settings.endGroup()
Use Qt::CheckState
def readSettings(self):
settings = QtCore.QSettings("file.ini")
settings.beginGroup("QCheckBox")
self.curvaturecheck.setCheckState(
settings.value("A", QtCore.Qt.Checked, QtCore.Qt.CheckState)
)
self.stiffnesscheck.setCheckState(
settings.value("B", QtCore.Qt.Unchecked, QtCore.Qt.CheckState)
)
self.simcurvaturecheck.setCheckState(
settings.value("C", QtCore.Qt.Unchecked, QtCore.Qt.CheckState)
)
settings.endGroup()
def writeSettings(self):
settings = QtCore.QSettings("file.ini")
settings.beginGroup("QCheckBox")
settings.setValue("A", self.curvaturecheck.checkState())
settings.setValue("B", self.stiffnesscheck.checkState())
settings.setValue("C", self.simcurvaturecheck.checkState())
settings.endGroup()
It is recommended that you delete the .ini file located in settings.fileName().
On the other hand it is not necessary to use lambda functions, change your code to:
self.curvaturecheck.stateChanged.connect(self.writeSettings)
self.stiffnesscheck.stateChanged.connect(self.writeSettings)
self.simcurvaturecheck.stateChanged.connect(self.writeSettings)
https://doc.qt.io/qt-5/qbuttongroup.html#details
QButtonGroup provides an abstract container into which button widgets can be placed.. It does not provide a visual representation of this container (see QGroupBox for a container widget), but instead manages the states of each of the buttons in the group.
setValue() on every checkbox can switch another.
But the real issue is isCheckable() (means can be checked or not). Probably you want to use isChecked() (value set to true).
EDIT. And you can try to set state by setChecked().
Or if you want to support partially checked use setCheckState() (as you used) with checkState() to get info.
Related
I am currently working on a PyQgis based standalone application and I need to add various QgsRubberBand to my Canvas.
I made a subclass of it : LineAnnotation.
The problem is that when I use the method "QgsMapCanvas.itemAt(event.pos() )" on a "canvasPressEvent", it returns a "qgis._gui.QgsRubberBand" object, not a "LineAnnotation".
Did I do something wrong ? The rest of my program can't work if it doesn't recognize that it's a LineAnnotation as it contains several new methods that I need to use.
Also I can't interact with the item at all, if I try to use one of the methods from QgsRubberBand, the application crashes.
Here is the code with the problem:
from qgis.gui import QgsMapCanvas, QgsLayerTreeMapCanvasBridge, QgsRubberBand
from qgis.core import QgsApplication, QgsProject, QgsPointXY, QgsGeometry
from qgis.PyQt.QtGui import QColor
import sys
class LineAnnotation(QgsRubberBand):
def __init__(self, canvas):
QgsRubberBand.__init__(self, canvas)
self.setColor(QColor("red") )
self.setWidth(10)
class Interface(QgsMapCanvas):
def __init__(self):
QgsMapCanvas.__init__(self)
self.setCanvasColor(QColor("#182F36") )
project_path = "project_path"
project = QgsProject.instance()
project.read(project_path)
layer_tree = QgsLayerTreeMapCanvasBridge(project.layerTreeRoot(), canvas=self)
layer_tree.setAutoSetupOnFirstLayer(False)
self.zoomToFeatureExtent(project.mapLayersByName('layer_name')[0].extent() )
self.enableAntiAliasing(True)
self.setAcceptDrops(True)
self.setParallelRenderingEnabled(True)
p1 = QgsPointXY(524670.46860305720474571, 5470375.41737424582242966)
p2 = QgsPointXY(589864.10151600651443005, 5487531.63656186405569315)
r = LineAnnotation(self)
r.setToGeometry(QgsGeometry.fromPolylineXY([p1, p2]) )
def mousePressEvent(self, event) -> None:
item = self.itemAt(event.pos() )
print(type(item) )
# Output is "<class 'qgis._gui.QgsRubberBand'>"
# Expected: "<class 'LineAnnotation'>"
class StackOverflow:
def __init__(self):
qgs = QgsApplication([], True)
qgs.setDoubleClickInterval(250)
qgs.initQgis()
graphicUI = Interface()
graphicUI.showMaximized()
sys.exit(qgs.exec_() )
if __name__ == '__main__':
app = StackOverflow()
> output: \<class 'qgis.\_gui.QgsRubberBand'\>
> Desired output: \<class 'lineAnnotation.LineAnnotation'\>
Problem seems to occur in versions prior to Qgis 3.26, my problem was solved after updating to latest version (3.28).
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()
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
I'm trying to create a GUI with QT Designer. I've converted my .ui designer file to a .py.
Here is my code:
from PyQt4.QtCore import QSettings, QTranslator, qVersion, QCoreApplication
from PyQt4.QtGui import QAction, QIcon
from qgis.core import *
import resources
from delete_feature_dialog import DeleteFeatureDialog
import os.path
class DeleteFeature:
def __init__(self, iface):
# Save reference to the QGIS interface
self.iface = iface
# Declare instance attributes
self.actions = []
self.menu = self.tr(u'&DeleteFeature')
self.toolbar = self.iface.addToolBar(u'DeleteFeature')
self.toolbar.setObjectName(u'DeleteFeature')
def add_action(
self,
icon_path,
text,
callback,
enabled_flag=True,
add_to_menu=True,
add_to_toolbar=True,
status_tip=None,
whats_this=None,
parent=None):
# Create the dialog (after translation) and keep reference
self.dlg = DeleteFeatureDialog()
....
return action
def initGui(self):
icon_path = ':/plugins/DeleteFeature/icon.png'
self.add_action(
icon_path,
text=self.tr(u''),
callback=self.run,
parent=self.iface.mainWindow())
def run(self):
#this code will populate the combo box with all vector layer
self.dlg.layerListCombo.clear()
layers = self.iface.legendInterface().layers()
layer_list = []
for layer in layers:
layerType = layer.type()
if layerType == QgsMapLayer.VectorLayer:
layer_list.append(layer.name())
self.dlg.layerListCombo.addItems(layer_list)
# show the dialog
self.dlg.show()
# Run the dialog event loop
result = self.dlg.exec_()
# See if OK was pressed
if result:
# Do something useful here - delete the line containing pass and
# substitute with your code.
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
selectedLayer = layers [selectedLayerIndex]
.....
Then when I open the plugin, I get the following error:
'DeleteFeatureDialog' objectObject has no attribute
'layerlistcombo'in QGIS Plugin
Any suggestion for this.
Seems that you wrote:
selectedLayerIndex = self.dlg.layerlistcombo.currentIndex()
but you should have written:
selectedLayerIndex = self.dlg.layerListCombo.currentIndex()
Like you did previously in your code (notice the Camel Notation when writing, not just lower-case letters), which is probably causing the No Attribute error you get.
Used: python 2.79, gtk 2.0
Dear python and PyGtk-users
In my program I want to give the opportunity to show searchresults of a great datafile in a gtk.TreeView using the method in the code. In the function that creates the ListStore I also create the csv-file the store is using. Now I can see, that the csv-file has changed after a new search with different keywords, but the TreeView does not, it still keeps the result of the first search, though I clear the store everytime self.search is running. It's really enerving if you need to restart the program for every new search...
I already tried some things, like creating a proper function for the datacreatin for the store, but nothing serves and the truth is that I don't have a lot of ideas...
And everything I found in the internet about this was about autorefreshing of the store with a timer or other topics more profound, seems like everyone instead of me knows how to do this...
Can anyone tell me, what mistake I am making? How do I refresh a TreeView?(as you can see self.search is called by a button...) here the relevant part of the code:
import gtk, csv
class BASE:
#...
#some other funtions, irrelevant for the problem
#...
def search(self, widget, event, data=None):
#...
#all the searchingstuff and the creation of 'inwrite.csv'
#...
with open('/home/emil/Documents/inwrite.csv', 'r') as storefile:
lines = storefile.readlines()
store = gtk.ListStore(str, str, str, str, str, str)
store.clear()
i=0
while i < len(lines):
line = [lines[i]]
csvfile = csv.reader(line, delimiter=',')
for row in csvfile:
temp = (row[0], row[1], row[2], row[3], row[4], row[5])
store.append(temp)
i = i + 1
self.tabview = gtk.TreeView(store)
self.tabview.set_rules_hint(True)
self.tabview.set_reorderable(True)
self.sw.add(self.tabview)
self.tabview.show()
self.create_columns(self.tabview)
def __init__(self):
#...
#creating the Window, entries,...
#...
self.button1 = gtk.Button('Buscar')
self.button1.connect('clicked', self.search, 'button 1')
#...
#packing and showing the whole GUI
#...
def create_columns(self, tabview):
rendererText = gtk.CellRendererText()
rendererText.props.wrap_width = 80
rendererText.props.wrap_mode = gtk.WRAP_WORD
column = gtk.TreeViewColumn('Codigo', rendererText, text=0)
column.set_sort_column_id(0)
self.tabview.append_column(column)
#...
#creating 5 more columns by the same principle
#...
def main(self):
gtk.main()
if __name__=='__main__':
base = BASE()
run = base
run.main()
thanks for your help, tell me if you need more information!
I do not know what is exactly wrong with your program (if you want to know that, you should provide a working minimal example).
Nevertheless, you do not need to manually update the TreeView because the TreeView always shows the content of the ListStore or TreeStore. You also do not have to create the ListStore everytime. You can create it one time and clear and insert the new entries when the event is emitted.
Here is a small example that shows how it works:
#from gi.repository import Gtk # uncomment to use PyGObject
import gtk as Gtk
class TestCase:
def __init__(self):
win = Gtk.Window()
button = Gtk.Button('Show')
button.connect('clicked', self.on_button_clicked)
self.clicked = 0
self.liststore = Gtk.ListStore(int)
self.liststore.append((self.clicked,))
view = Gtk.TreeView(self.liststore)
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn('demo', renderer, text=0)
view.append_column(column)
box = Gtk.HBox()
box.pack_start(button, True, True, 0)
box.pack_start(view, True, True, 0)
win.add(box)
win.connect('delete-event', Gtk.main_quit)
win.show_all()
def on_button_clicked(self, button):
self.clicked += 1
self.liststore.clear()
self.liststore.append((self.clicked,))
if __name__ == "__main__":
TestCase()
Gtk.main()
It also seems that you first create your csv file and read it afterwards. I don't know about the rest of your program but it is probably better to use the data directly and insert it into the ListStore and not read it from the csv file. It might be even possible then to just remove and insert the new entries and not clear the whole ListStore and insert everything again. That would be more efficient with bigger amounts of data.