PyQt: most efficient delete sql query - python

I'm using pyqt4, qt designer and postgresql database. I've managed to make part of my GUI which inserts new data to my db, but now I'd like to try something else for my Delete section of GUI. Since I'm into python/pyqt for maybe a week now I'll try to explain what I'm looking for as simple as possible. First off: here is part of my code which I used for adding data:
...
class database_GUI(QtGui.QWidget, Ui_Main_GUI_Widget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.setupUi(self)
self.Add_button.clicked.connect(self.open_sub_ui)
def open_sub_ui(self):
if self.Add_comboBox.currentText() == "kirurg":
global kirurg
kirurg = kirurg_GUI()
kirurg.show()
...
class kirurg_GUI(QtGui.QWidget, Ui_kirurg_Widget):
def __init__(self):
QtGui.QWidget.__init__(self)
self.setupUi(self)
self.kirurg_Add_button.clicked.connect(self.insert_kirurg)
def insert_kirurg(self):
oib_kir = self.kirurg_oib_kir_lineEdit.text()
if not oib_kir:
QtGui.QMessageBox.critical(self, 'Query error', 'oib_kir must not be empty')
else:
query = QSqlQuery()
status = query.exec("INSERT INTO kirurg (oib_kir, prezime, ime, adresa, broj_telefona)"
"VALUES ('%s', '%s', '%s', '%s', '%s')" % (''.join(self.kirurg_oib_kir_lineEdit.text()),
''.join(self.kirurg_prezime_lineEdit.text()),
''.join(self.kirurg_ime_lineEdit.text()),
''.join(self.kirurg_adresa_lineEdit.text()),
''.join(self.kirurg_broj_telefona_lineEdit.text())))
if status is not True:
errorText = query.lastError().text()
QtGui.QMessageBox.critical(self, 'Query error', errorText)
So basically, new GUI would open for every other comboBox option. If user selects comboBox option 1 and clicks Add, it opens GUI for adding data to table number 1, if user selects comboBox option 2 and clicks Add, it opens GUI for adding data to table number 2, and so on.
But, I'd like to be more flexibile with my Delete GUI so I was wondering is it possible to make something like this:
query.exec("DELETE FROM ('%s') WHERE ('%s) = ('%s'))
These ('%s') things should be strings, which my program would read from lineEdit.text(). So basically, program would read data that user enters in lineEdit and according to them it would know which row of data to delete and from which table. I hope you can see my point and question here. If it's not possible, I guess I'll just make another 12 copy pasted GUI's for each table, but I'm hoping there's better solution to that.

Related

PyQt Quickly Update QTextEdit like QAbstractItemModel

Is there any way to make a model to update a QTextEdit like the QAbstractItemModel.
The QAbstractItemModel/QAbstractTableModel has a data (index[, role=Qt.DisplayRole]) method which is called whenever the view needs to display something. This allows me to make my own data structure to save data in python quickly. Is there any way to make a QTextEdit, QTextDocument, or QTextDocumentLayout work this way?
Right now I save data to a queue and periodically display the data by running update_display on a timer.
class QuickTextEdit(QtWidgets.QTextEdit):
def update_display(self):
for _ in range(len(self.queue)):
text, fmt = self.queue.popleft()
cursor = QtGui.QTextCursor(self.textCursor())
cursor.beginEditBlock()
# Move and check the position
pos = cursor.position()
cursor.movePosition(QtGui.QTextCursor.End)
is_end = cursor.position() == pos
# Insert the text
cursor.setCharFormat(fmt)
cursor.insertText(text)
cursor.endEditBlock()
# Move the cursor
if is_end:
# Actually move the text cursor
cursor.movePosition(QtGui.QTextCursor.End)
self.setTextCursor(cursor)
I found that this is much slower than the way a QAbstractTableModel/QTableView works.
I would like the widget to request data (instead of inserting) like the QAbstractItemModel. I tried using an html string in a QLabel.paintEvent, but couldn't get that to work properly. I really would just like an HTML Text Viewer for some data structure/model.
class QuickTextEdit(QtWidgets.QTextEdit):
def data(self):
return ''.join(('<font color="{color}">{text}</font>'.format(color=color, text=text)
for color, text in self.queue))
You can implement a simple model view setup yourself.
Here is some pseudo code:
class TextEditView(QtWidgets.QTextEdit):
def __init__(self, model):
connect(model.dataChanged, self.update_display)
#SLOT
def update_display(self):
text = model.data()
self.setText(text)
class TextEditModel(QObject):
SIGNAL dataChanged
def data(self):
new_text = queue.get_nowait()
return new_text
class WorkerThread(QtCore.QThread):
def run(self):
queue.put(new_data)
model.dataChanged.emit(index, index)
Then in your thread you would first put the new data into the queue. And then issue a model.dataChanged signal. Then the view would poll the new data.
Alternatively you can skip the whole Model view separation and create a signal for TextEditView with the datatype you want.
Let me know how it goes.

How to shared data between instances classes (backend) and Kivy graphical elements (frontend)?

I'm a beginner with Kivy and I'm trying to create gui for a python app.
I have a backend programmed in python, working alone (keyboard as input) and now I want frontend with kivy. I have two questions:
- How can I run both components (back and front end) at once?
- How can I share objects of existing classes in my backend to display information in the frontend (kivy)?
classtest.py
class Test(object):
def __init__(self, attr):
self.attr = attr
gui.py
class LoginScreen(GridLayout):
def __init__(self, **kwargs):
super(LoginScreen, self).__init__(**kwargs)
self.cols = 2
self.add_widget(Label(text='User Name'))
self.username = TextInput(multiline=False)
self.add_widget(self.username)
self.add_widget(Label(text='password'))
self.password = TextInput(password=True, multiline=False)
self.add_widget(self.password)
print self.username.text
class Login(App):
def build(self):
Window.borderless = True
return LoginScreen()
main.py
import classtest, gui
users = ['user_name1', 'user_name2', 'user_name3']
gui.Login().run()
for u in users:
test = classtest.Test(u) # this should update the user text field on the windows login automatically, but how?
In example, How can I update an element of the login window when an instance attribute value change?
Thanks many many times!
It won't update because... of a loop :P Kivy for each App().run() or a similar "run" command launches a loop and your:
for u in users:
test = classtest.Test(u)
is written after that loop. So basically it won't even execute while your app is running. Just put print('something') into that for loop and you'll see.
Example:
while True:
<do something>
<change a variable in that loop> # == nope
Which for you means that you need either:
write that into gui.py file or
set those things right in the classtest.py
The second option also depends when you use the class. If outside of the main loop, then you are in the same situation as right now, therefore - use that Test() inside of gui.py.
You won't be able to use any code after run() while the app is running. Maybe with some dirty trick, but that will bring you only troubles. The code you wrote could be used in some "cleaning", which you can also do in App.on_stop method(inside main loop).

Handling mysql using PyQt4

So, I have a mysql database patients where is a client table. I need to show information about clients in GUI window in table. Also I need a filter by main fields to get more detailed information (separately surname, name, series of documents, a series of policy, etc.) with the possibility to search simultaneously in multiple fields. I started with code below.
The question number 1 is: What is easy to use in this task - QSqlTableModel or just QTableWidget?
The question number 2 is: How to filter by main fields? What that mean?
I would be very glad to any thoughts on the subject.
from PyQt4.QtGui import *
from PyQt4.QtSql import *
import sys
def main_():
app = QApplication(sys.argv)
table = QTableWidget()
db = QSqlDatabase.addDatabase("QMYSQL")
db.setHostName("127.0.0.1")
db.setDatabaseName("patients")
db.setUserName("root")
db.setPassword("")
table_name = "client"
if (db.open()==False):
QMessageBox.critical(None, "Database Error",
db.lastError().text())
query = QSqlQuery ("select * from "+ table_name + " limit 10")
table.setColumnCount(query.record().count())
table.setRowCount(query.size())
index=0
while (query.next()):
table.setItem(index,0,QTableWidgetItem(query.value(0).toString()))
table.setItem(index,1,QTableWidgetItem(query.value(1).toString()))
index += 1
table.show()
return app.exec_()
if __name__ == '__main__':
main_()
I think you would like to read more about Model-View concept.
After opening your database connection, you create a model of the data, then attach it to the view... no iterating needed:
model = QtSql.QSqlTableModel()
# selecting a table
model.setTable("clients")
# applying a filter
model.setFilter("id > 0")
# i.e.: executing the query
model.select()
# the widget to show the data
tableView = QTableView()
# attach the model to widget
tableView.setModel(model)
tableView.show()
Also: if you cannot open the database - exit the program, not only present a message box.
I hope that helps a bit.

How to record multiple checkboxes in wxPython?

I am trying to get my program to record if the user clicked on checkbox(es) so I know what things to delete. The problem is that I don't have all the variables names for all the checkboxes so I can't just do GetValue(). In the code below, I have a set number of things but in the actual program, it pulls user info from file.
import wx
class supper(wx.Frame):
def __init__(self,parent,id):
wx.Frame.__init__(self,parent,id,'Delete Stocks',size=(300,300))
nexus=wx.Panel(self)
again=30
newfp='GOOG AAPL'.split()
#Need to see if user checked box and which one
for i in newfp:
self.checkbox=(wx.CheckBox(nexus,-1,i,(30,again),(160,-1)))
self.Bind(wx.EVT_CHECKBOX, self.lol,self.checkbox)
again+=30
anothercancel=wx.Button(nexus,label='Cancel',pos=(50,250),size=(60,40))
self.Bind(wx.EVT_BUTTON,self.acancel,anothercancel)
anotherok=wx.Button(nexus,label='OK',pos=(200,250),size=(60,40))
self.Bind(wx.EVT_BUTTON,self.okalready,anotherok)
def acancel(self,event):
self.Destroy()
#Couldn't figure out how to see what check was clicked
def okalready(self,event):
for i in newfp:
valuechecker=self.checkbox.GetValue()
if self.checkbox.Get()==True:
print 'You clicked this %s one'%i
self.Destroy()
def lol(self,event):
pass
if __name__=='__main__':
ok=wx.PySimpleApp()
people=supper(parent=None,id=-1)
people.Show()
ok.MainLoop()
This isn't the whole thing so there might be a variable that is not defined here. Thanks in advance! Look forward to the answers!
just keep them in a list ...
self.checkboxes = []
for i in newfp:
self.checkboxes.append(wx.CheckBox(nexus,-1,i,(30,again),(160,-1)))
self.checkboxes[-1].Bind(wx.EVT_CHECKBOX, self.lol)
again+=30
then to check which boxes are checked when you click ok you can use this
def okalready(self,event):
for i,cb in enumerate(self.checkboxes):
print "CB:%d = %s"%(i,cb.GetValue())
print "Checked:",[cb.GetLabel() for cb in self.checkboxes if cb.GetValue()]
self.Destroy()

Simple, versatile and re-usable entry dialog (sometimes referred to as input dialog) in PyGTK

I am searching for a simple dialog with a text entry widget asking the user for some input. The dialog should be easy to run (like the gtk.MessageDialog variants) and as flexible.
There are of course some examples but they are either not flexible enough or too complicated to construct for my taste.
I hate re-inventing the wheel... or a dialog.
Based on an example I found (thanks Ardoris!), I came up with a dialog subclass... hope it helps someone out there!
#!/usr/bin/env python
import gtk
class EntryDialog(gtk.MessageDialog):
def __init__(self, *args, **kwargs):
'''
Creates a new EntryDialog. Takes all the arguments of the usual
MessageDialog constructor plus one optional named argument
"default_value" to specify the initial contents of the entry.
'''
if 'default_value' in kwargs:
default_value = kwargs['default_value']
del kwargs['default_value']
else:
default_value = ''
super(EntryDialog, self).__init__(*args, **kwargs)
entry = gtk.Entry()
entry.set_text(str(default_value))
entry.connect("activate",
lambda ent, dlg, resp: dlg.response(resp),
self, gtk.RESPONSE_OK)
self.vbox.pack_end(entry, True, True, 0)
self.vbox.show_all()
self.entry = entry
def set_value(self, text):
self.entry.set_text(text)
def run(self):
result = super(EntryDialog, self).run()
if result == gtk.RESPONSE_OK:
text = self.entry.get_text()
else:
text = None
return text
The run() method returns either the text entered in the entry box if the user presses <Enter> or clicks Ok. If Cancel is clicked or <Esc> pressed, the run() method returns None.
Except for that, the dialog should behave as any other gtk.MessageDialog instance.
Maybe that is not very general as it assumes you will always have Ok as an option, but that is what I need in 99% of my use cases anyway.
There isn't one available in GTK+. You've got two options:
Create a dialog, pack the Entry and any other content you need (probably the best way in my opinion)
Retrieve the content_area of the MessageDialog and append an Entry to it.
Something along the lines of:
#!/usr/bin/env python
import gtk
messagedialog = gtk.MessageDialog(parent=None, flags=0, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK, message_format="Hello")
action_area = messagedialog.get_content_area()
entry = gtk.Entry()
action_area.pack_start(entry)
messagedialog.show_all()
messagedialog.run()
messagedialog.destroy()
Though it does probably need more refinement to get the Entry to display nicely.
Here's the function I wrote, based on the previous answers here. It's a function instead of a class, which means you can use it in one line.
def get_text(parent, message, default=''):
"""
Display a dialog with a text entry.
Returns the text, or None if canceled.
"""
d = gtk.MessageDialog(parent,
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
gtk.MESSAGE_QUESTION,
gtk.BUTTONS_OK_CANCEL,
message)
entry = gtk.Entry()
entry.set_text(default)
entry.show()
d.vbox.pack_end(entry)
entry.connect('activate', lambda _: d.response(gtk.RESPONSE_OK))
d.set_default_response(gtk.RESPONSE_OK)
r = d.run()
text = entry.get_text().decode('utf8')
d.destroy()
if r == gtk.RESPONSE_OK:
return text
else:
return None

Categories