Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie

Python: help passing update values back and updating

Options
  • 05-02-2015 9:41pm
    #1
    Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭


    I'm just trying to get to grips with some basic Python (on GTK) after having not programmed in years. I'm putting together a small application that searches a user given string in a database and returns the search result. I get as far as sending the search string down to a function, pulling the result from the DB and assigning it to a string. However, I'm not sure how I go about retrieving the result from the main part of the program and updating a widget with the returned text.

    This part of the main code sends the search result to one of two functions depending on if Enter is hit or the search icon is clicked.
    #Add Search box
            entry = Gtk.Entry()
            entry.set_property("secondary-icon-stock", Gtk.STOCK_FIND)
            entry.connect("icon-press", self.on_search_button)
            entry.connect("activate", self.on_search_enter)
    

    The search function takes in the search text and calls the lookup function.
    def on_search_enter(self, entry):
            search = entry.get_text()
            entry.set_text("")
            print("Search for " + search)
            result = self.lookup_player(search, entry)
            print result
    

    So here I'm trying to pass the string, the entry box object and get back the result, a string called playername which I (temporarily) display on a label which is displayed in a table, both of which are part of the main body, as is the string.
        def lookup_player(self, pstring, entry):
            try:
                con = psycopg2.connect(database='Rugby', user='postgres', password = '1234')
                cur = con.cursor()
                search = "select firstname, lastname from player where firstname ilike '" + pstring + "' or lastname ilike '" + pstring + "'"
                print search
                cur.execute(search)
                ver = cur.fetchall()
                entry.playername = ver
                print ver
    

    So, that's confusing to read...

    Basically, how to get that string read from the database back to the main body and force an existing label to update with the returned string.


Comments

  • Registered Users Posts: 6,013 ✭✭✭Talisman


    Basically, how to get that string read from the database back to the main body
    Inside your function you want to return the result and not print it, so using the last line of the lookup_player function should be:
    return ver
    
    and force an existing label to update with the returned string.
    The documentation can help you. The set_label() method sets the text of the label.

    Learn Python the Hard Way is a great free resource for learning Python.


  • Moderators, Science, Health & Environment Moderators, Social & Fun Moderators, Society & Culture Moderators Posts: 60,082 Mod ✭✭✭✭Tar.Aldarion


    Good book, fast and simple.
    Afer you change to return ver, do a call like this:
    result = lookup_player(<params>)
    


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    Yeah, I think I need to read that book start to finish. I can't get the widget I want to update to be recognised by anything outside of main and the whole notion of ordering of functions and scope of variables is lost on me for the moment.


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    I keep thinking I'm getting the hang of this and have written a good bit more but I keep coming back around to this one problem. Once I've passed the ListStore to the function which retrieves the results and appends them I return that ListStore. However, when it's picked up by the main, the ListStore becomes a useless long that I can do nothing with.

    in the function I have
    store.append([result[i][0],result[i][1],str(result[i][4])])
    

    (I also tried with
    treeiter=store.append([result[i][0],result[i][1],str(result[i][4])])
    

    but I find that kind of useless as it just keeps track of the last added result ?? )

    then if I
    print len(store)
    

    it correctly gives me 2, the number of results

    I then
    return store
    

    However, back in the main part,
    store=entry.connect("activate", self.on_search_enter,store)
    

    the store then becomes a long and I can neither get its length nor read its contents.

    So something must be wrong with the way I'm assigning the returned value from the function called on pressing Enter. I can't make out what it is after 3 days of reading...


  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    However, back in the main part,
    store=entry.connect("activate", self.on_search_enter,store)
    

    the store then becomes a long and I can neither get its length nor read its contents.

    The quoted line of code is an assignment operation. You're saying "call the 'connect' method of the 'entry' object, passing it three arguments - the literal string 'activate'; the 'on_search_enter' attribute of the object on which the current method is executing; and the list called 'store' - and place the value returned by the 'connect' method in the variable called 'store'.

    So while 'store' contains a list before you pass it to the method, once you assign the long value that's returned by 'connect' to it, it's going to contain that long value and not the list anymore.


  • Advertisement
  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    OK, that makes sense. But I still don't get how I'm meant to use the value of store once it's been modified by the on_search_enter


  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    I have to admit at this point that it's not clear enough to me from the code snippets you're posting what you're trying to achieve.

    I get that there's an "activate" signal handler called "on_search_enter" that's being passed the "store" value, but I'm not sure what that handler is doing with store - are you trying to modify it there and expecting the modifications to be returned? Because I don't think that's what event handlers are supposed to do.

    Can you flesh the explanation out a bit?


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    Sorry about the vagueness!

    In simple terms I have a text input box (entry) and hitting Enter on it triggers a function which looks up the search term in a database and puts the results into 'store'. (Store is a GTK Object which takes a mix of variable in so they can be used for various things)

    The results then need to be displayed in a dialog (which has been predefined in the main part of the program). From there, clicking on a result displays details of the searched item in another dialog in the main screen.

    So once I have put the results in the store I need to pass them back to the main so it can display them.
    are you trying to modify it there and expecting the modifications to be returned?
    Yes, and it doesn't work. It's a flawed concept but I can't find the right way to do it.


  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    OK, two things occur to me: one is that you could make "store" a global variable rather than passing it to the event handler. The other possibility is that, rather than have the event handler trying to return the values to the main function so that it can display them, maybe the event handler should do it itself?


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    Are global variables allowed these days? We had it beaten into us that they were the tool of the devil. Variables in python tend to only last a few lines before being replaced by other variables of the same name although I could just give unique names I suppose.

    I had been trying to do the second option but I would need to pass every single element of the main (about 8 widgets) to each function in turn in that case, which makes for very awkward code.


  • Advertisement
  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    I hear you - neither option sounded appealing as I was suggesting them, but without a wider view of the code, I can't really think of anything else. I tend to find that when I come up against problems with ugly solutions, it's because I painted myself into a corner with a design decision earlier.


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    Yep, reworking it a bit so only the outermost visual elements are created in the main and the ephemeral stuff is created on the fly in the other functions. This way I only need to pass a minimum of parameters down (and hope they get modified!)


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    I give up. There's just no way to design this so that the main function knows anything about what's happening below it. I can pass widgets all day long to a function but they'll never come back.


  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    Do you want to PM me a link to the code you've written, and I can have a look?


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    I have to versions I'm playing around with, one of which is this one
    http://pastebin.com/q5bnLxaB
    and the other which just uses the commented text to create a widget outside rather than inside the search function

    If you change line 64 to assign three items directly to the store (string, string, date) it should bypass the database.


  • Technology & Internet Moderators Posts: 28,791 Mod ✭✭✭✭oscarBravo


    OK - I don't really have time today (sorry!) to hack at it, but some quick feedback: rather than pass around Gtk objects between methods of the NotebookWindow class, just make those objects attributes of the class instance and let the methods access them directly.

    For example, you're passing the 'table' object, a Gtk.Table, to the on_search_enter event handler. Instead of doing that, change line 30 from
    table = Gtk.Table(rows=40, columns=10)
    
    to
    self.table = Gtk.Table(rows=40, columns=10)
    
    Then, instead of passing 'table' as an argument to 'on_search_enter', have that function refer to 'self.table'.

    Basically, my instinct would be to make most if not all of the controls instance attributes rather than just creating them ephemerally in the __init__ method. That way, if you need to access any of them in any other method - including any event handler - you can just use self.<whatever> to get to it.

    It's sort of what I was getting at with talk of a global variable earlier, except that it's only 'global' to the class instance, which is absolutely acceptable.

    Let me know if that makes any sense.


  • Moderators, Arts Moderators Posts: 35,120 Mod ✭✭✭✭pickarooney


    The program has become self aware.
    I had been using 'self' intermittently without really knowing what purpose it served but I've finally copped it now, thanks! So with a small bit of rearranging, the widgets are all pre-cooked and the search is able to write to, clear and update the results box :)


Advertisement