Passing of a variable (an ID) to another compiled UI in pyqt - python

I've been stumped for more than an hour on how to pass a variable, specifically an ID in sqlite which was recently accessed, to be used to another UI generated. I'm using eric4 (with python, pyqt, qtdesigner and sqlite).
Basically the program I'm coding makes members and each member has a unique ID when the information of the member is generated. When there is a new member made, the ID assigned to the new member must be passed to another part of the program. But there are also instances where there must be modifications made in the member, the ID must be known to display the right information of the member.
Basically, when a new member is added, it first inputs the the information in the database. What I did is like this in the dialog code of that ui named newmember.py:
def on_button_Save_released(self):
Nik = unicode(self.LineEdit_Nickname.text())
self.NMem = NewMem()
self.NMem.input_data(Nik)
self.close()
The NewMem is a class in another py file which has access to the database. Parts of the input_data method goes like this:
cur.execute("insert into Members (Nick) values (?)",(Nik))
I added this code so that it will know what ID the new member is assigned::
CurrentID = cur.lastrowid
return CurrentID
So I changed this line self.NMem.input_data(Nik) in the ui dialog code newmember.py into this
ID = self.NMem.input_data(Nik)
so that the ID will be passed.
Now, the dialog code will open another window and I want the returned ID be used to another ui. Basically the whole method in ui dialog code in newmember.py is like this so far:
def on_button_Save_released(self):
Nik = unicode(self.LineEdit_Nickname.text())
self.NMem = NewMem()
ID = self.NMem.input_data(Nik)
self.close()
self.Pts = Points()
self.Pts.show()
The Points() is a class in another ui dialog code which will show in the Points ui the information of the member. But the returned ID information must be passed to the Points() ui so that the right information be displayed. I have a hunch that I would be needing to change some parts in the compiled ui form so that it knows the ID to be displayed but how will I pass it in there compiled ui form?
Any help is very much appreciated bows deeply
Edit: Is there a way in this code -
self.Pts = Points()
self.Pts.show()
be the variable ID be also incorporated and will pass into the ui? Like
self.Pts = Points
self.Pts.show(ID)
that the ID will be going to the ui also?
Edit2: Is there a way how to pass variables in classes of a ui in python just like how it was shown here - http://www.daniweb.com/forums/thread64758.html

I believe using a Qt model with a QDataWidgetMapper is the Qt way of solving this problem. An example here. (QSLTableModel or subclass QAbstractTableModel if you want to program the database communication yourself).
You can also check SQL Widget mapper example in the Qt docs.
Personally I prefer to use a custom model because I've previously stumbled upon deployment problems using Qt's SQL, but your mileage may vary.

Related

How to Set and Get "comment" text using setText?

I am trying to store string data within a QAbstractButton.text().
Why?
I want to display the short name in the text() itself, but be able to call the long name via the text() "comment" through code.
You are able to write "comments" within QT Designer, but I have been unable to replicate this in Python.
Looking at the code in notepad, it appears the "comment" text is created within the text string itself:
<property name="text">
<string extracomment="toast">Select object and click here</string>
What I currently have in python is:
Xsl = cmds.ls(sl=1)[0]
Xbutton.setText(Xsl)
How can I also set and get the comment part of this text?
Any advice would be appreciated!
If you want to add extra data to a widget why not just subclass it and create your own?
class MyCustomButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super(MyCustomButton, self).__init__(parent)
self.my_variable = None
Now you can continue using MyCustomButton just like a normal button, and also add whatever you like to my_variable.
I have found that every object contains a variable for windowTitle. If this isn't the main window, the window title is generally left blank, therefore I can store data here.
Granted, this probably isn't the cleanest approach, but it'll serve for now.
Green Cell's subclassing is most likely the best way to resolve this issue. However, I am mainly building the UI using Qt Designer, and want to primarily keep any edits within that wrapper.
def store_selected_node_on_button(self):
"""
Changes the text of a given button to store an object's name
As the button isn't a window, I can set the window title to store the long name of the selected object.
:return: None
"""
button = self.sender()
sl = cmds.ls(sl=1, long=True)
if not sl:
button.setText("Select object and click here")
button.setWindowTitle("")
else:
button.setText(sl[0].split("|")[-1])
button.setWindowTitle(sl[0])
return

Odoo - Changing user group id just right after signup (ecommerce)

I'm using Odoo 10. After a new user sign up (through localhost:8069/web/signup) i want him to be automatically allocated inside a group i created on my very own custom module (the user will need authentication from an admin later on so he can be converted to a regular portal user; after signup he will receive restricted access).
I have tried many things. My latest effort looks like this:
class RestrictAccessOnSignup(auth_signup_controller.AuthSignupHome):
def do_signup(self, *args):
super(RestrictAccessOnSignup, self).do_signup(*args)
request.env['res.groups'].sudo().write({'groups_id': 'group_unuser'})
Note that I have import odoo.addons.auth_signup.controllers.main as auth_signup_controller so that I can override the auth_signup controller.
I have located that method as the responsible for doing the signup. So I call it in my new method and then try to change the newly created user's group_id.
What i miss is a fundamental understanding of how to overwrite a field's value from another model inside a controller method context. I'm using the 'request' object although i'm not sure of it. I have seen people using 'self.pool['res.users'] (e.g.) for such purposes but i don't understand how to apply it inside my problem's context.
I believe, also, that there is a way to change the default group for a user after it is created (i would like to know), but i also want to understand how to solve the general problem (accessing and overwriting a field's value from another module).
Another weird thing is that the field groups_id does exist in 'res.users' model, but it does not appear as a column in my pgAdmin interface when i click to see the 'res.users' table... Any idea why?
Thanks a lot!
i don't know if after calling :
super(RestrictAccessOnSignup,self).do_signup(*args)
you will have access to user record in request object but if so just add
the group to user like this, if not you have to find where the user record or id is saved after calling do_signup because you need to update that record to ad this group.
# create env variable i hate typing even i'm typing here ^^
env = request.env
env.user.sudo().write({'groups_id': [
# in odoo relation field accept a list of commands
# command 4 means add the id in the second position must be an integer
# ref return an object so we return the id
( 4, env.ref('your_module_name.group_unuser').id),
]
})
and if changes are not committed in database you may need to commit them
request.env.cr.commit()
Note: self.env.ref you must pass the full xmlID.
This is what worked for me:
def do_signup(self, *args):
super(RestrictAccessOnSignup, self).do_signup(*args)
group_id = request.env['ir.model.data'].get_object('academy2', 'group_unuser')
group_id.sudo().write({'users': [(4, request.env.uid)]})
In the get_object i pass as arguments the 'module' and the 'xmlID' of the group i want to fetch.
It is still not clear to me why 'ir.model.data' is the environment used, but this works as a charm. Please note that here we are adding a user to the group, and not a group to the user, and to me that actually makes more sense.
Any further elucidation or parallel solutions are welcome, the methods aren't as clear to me as they should be.
thanks.

python load from shelve - can I retain the variable name?

I'm teaching myself how to write a basic game in python (text based - not using pygame). (Note: I haven't actually gotten to the "game" part per-se, because I wanted to make sure I have the basic core structure figured out first.)
I'm at the point where I'm trying to figure out how I might implement a save/load scenario so a game session could persist beyond a signle running of the program. I did a bit of searching and everything seems to point to pickling or shelving as the best solutions.
My test scenario is for saving and loading a single instance of a class. Specifically, I have a class called Characters(), and (for testing's sake) a sigle instance of that class assigned to a variable called pc. Instances of the Character class have an attribute called name which is originally set to "DEFAULT", but will be updated based on user input at the initial setup of a new game. For ex:
class Characters(object):
def __init__(self):
self.name = "DEFAULT"
pc = Characters()
pc.name = "Bob"
I also have (or will have) a large number of functions that refer to various instances using the variables they are asigned to. For example, a made up one as a simplified example might be:
def print_name(character):
print character.name
def run():
print_name(pc)
run()
I plan to have a save function that will pack up the pc instance (among other info) with their current info (ex: with the updated name). I also will have a load function that would allow a user to play a saved game instead of starting a new one. From what I read, the load could work something like this:
*assuming info was saved to a file called "save1"
*assuming the pc instance was shelved with "pc" as the key
import shelve
mysave = shelve.open("save1")
pc = mysave["pc"]
My question is, is there a way for the shelve load to "remember" the variable name assotiated with the instance, and automatically do that << pc = mysave["pc"] >> step? Or a way for me to store that variable name as a string (ex as the key) and somehow use that string to create the variable with the correct name (pc)?
I will need to "save" a LOT of instances, and can automate that process with a loop, but I don't know how to automate the unloading to specific variable names. Do I really have to re-asign each one individually and explicitly? I need to asign the instances back to the apropriate variable names bc I have a bunch of core functions that refer to specific instances using variable names (like the example I gave above).
Ideas? Is this possible, or is there an entirely different solution that I'm not seeing?
Thanks!
~ribs
Sure, it's possible to do something like that. Since a shelf itself is like a dictionary, just save all the character instances in a real dictionary instance inside it using their variable's name as the key. For example:
class Character(object):
def __init__(self, name="DEFAULT"):
self.name = name
pc = Character("Bob")
def print_name(character):
print character.name
def run():
print_name(pc)
run()
import shelve
mysave = shelve.open("save1")
# save all Character instances without the default name
mysave["all characters"] = {varname:value for varname,value in
globals().iteritems() if
isinstance(value, Character) and
value.name != "DEFAULT"}
mysave.close()
del pc
mysave = shelve.open("save1")
globals().update(mysave["all characters"])
mysave.close()
run()

Django custom method won't show up

I have two custom methods for a model manager in Django. One of them works. I recently added another and Django (and python) act like it doesn't exist. Here's the relevant part of the model:
class FigureServerManager(models.Manager):
#This method takes as input a user and grabs a figure that is not marked complete for which that user has not already submitted a result
def serve_to_user(self,user):
not_complete=super(FigureServerManager, self).get_query_set().filter(complete=0)
for Figure in not_complete:
checkifresult=User.objects.get(pk=user).result_set.all().filter(figure=Figure.id)
if not checkifresult:
return Figure
#This is a copy of the above method that I want to change to do something else, but I can't even get it to show up yet
def serve_training_task(self, user):
with_correct_ans=super(FigureServerManager, self).get_query_set().filter(complete=0)
for Figure in with_correct_ans:
checkifresult=User.objects.get(pk=user).result_set.all().filter(figure=Figure.id)
if not checkifresult:
return Figure
class Figure(models.Model):
doi=models.CharField(max_length=20)
url=models.CharField(max_length=200)
image=models.ImageField(upload_to='classify')
complete=models.BooleanField()
#include the default manager
objects=models.Manager()
#add the extra one for serving figures
serve_objects=FigureServerManager()
I get an error on the website (running the Django development server) like this:
'FigureServerManager' object has no attribute 'serve_training_task'
and if I run dir(FigureServerManager) in python the serve_training_task method does not appear but the serve_to_user method does appear. Why doesn't serve_training_task work?
Python Language Reference, ยง2.1.8: "Indentation"

PyQt4: My database displays empty cells

I am using the pyqt4 framework to do some displays for database forms. Unfortunately, I hit a snag while trying to filter and display my database by last name. Assume that the database connection works. Also assume that I have the correct amount of items in my tupleHeader since I use the same initializeModel method for other methods (like the search() function described below, and it works fine.
I call the display() function and it works perfectly fine, but when creating a proxyModel from the sourceModel, and trying to display the proxyModel with my search function, I have empty cells displayed. When I restrict my search so that it filters half my database, it shows that many cells (so most of this is working). But it will not display anything from the database itself.
Below is some of my code:
from PyQt4 import QtGui, QtCore, QtSql
self.caseSensitivity = QtCore.Qt.CaseInsensitive
self.syntax = QtCore.QRegExp.FixedString
def initializeModel(self, model):
model.setTable(self.table)
#model.setEditStrategy(QtSql.QSqlTableModel.OnManualSubmit)
b = 0
for a in self.tupleHeader:
model.setHeaderData(b, QtCore.Qt.Horizontal, QtGui.qApp.tr(a))
b += 1
model.select()
def display(self):
'''reads all row data and displays it on a tableview'''
self.connectdb(self.db, self.localhost, self.dbname, self.username, self.password)
model = QtSql.QSqlTableModel()
self.initializeModel(model)
self.view.setModel(model)
self.disconnectdb(self.db)
def search(self, searchQuery):
'''queries database data, filters it, and displays it on a tableview'''
sourceModel = QtSql.QSqlTableModel()
proxyModel = QtGui.QSortFilterProxyModel()
self.initializeModel(sourceModel)
proxyModel.setSourceModel(sourceModel) # allows to edit proxyModel without changing underying model
#searchQuery contains the last name that I am filtering with
regExp = QtCore.QRegExp(searchQuery, self.caseSensitivity, self.syntax)
proxyModel.setFilterRegExp(regExp)
proxyModel.setFilterKeyColumn(2) # this column holds the last names
# self.view contains the table itemview my application uses to display the database
self.view.setModel(proxyModel)
EDIT: I am not interested in keeping this piece of code, I just want to know why it allows the table to show the table's content instead of a bunch of empty cells
print self.proxyModel.filterAcceptsRow(2, self.sourceModel)
Also, if you put in this after the last statement ( self.view.setModel(proxyModel) ), it will show the table, even if it does send an error:
print self.proxyModel.filterAcceptsRow(2, self.sourceModel)
TypeError: QSortFilterProxyModel.filterAcceptsRow(int, QModelIndex): argument 2 has unexpected type 'QSqlTableModel'
It doesn't matter what the arguments are or whether I use filterAcceptsRow ro filterAcceptsColumn, it displays the table. Does this narrow down the problem some?
Thank you for your time searching for this coding error/bug, and happy hunting!
While I could not find the solution to my problem, it solved itself. I am not certain, but I think it was this code snippet that made it work.
self.dbmanip = CoreDB(self.userTableView, self.table)
This was put inside of the SetupUi() method created by the Qt4 Designer. I think either the dbmanip that contained the TableView lost the information from the proxyModel, or (more likely), I may have referenced the wrong table between the proxyModel and the original Model (that created the proxyModel), and then couldn't display because it was calling the cell structure from one table and the actual information from another.
These are all guesses though. Still, problem solved.

Categories