PyQt iterate over a a QTreeView with checkbox - checkbox

i am trying to make a UI that display folders from a given directory,
and the user can check or uncheck the folder.
i would like to get the information of what was checked and return the folder
i know i can loop / iterate in a QTableWidget, but if its a view, or its comming from a Qt.Dir how its done?
(even might be a easier way to add the check boxes to the dir view model than making another class)
thanks.
from PyQt4 import QtCore, QtGui
import sys
import argparse
def parseOpt():
parser = argparse.ArgumentParser(description="Check if the files in this folder are valid EXRs")
parser.add_argument("-file", dest="filepath", help="The file path to be checked.")
return parser.parse_args()
ARGS = parseOpt()
class CheckableDirModel(QtGui.QDirModel):
#a class to put checkbox on the folders
def __init__(self, parent=None):
QtGui.QDirModel.__init__(self, None)
self.checks = {}
def data(self, index, role=QtCore.Qt.DisplayRole):
if role != QtCore.Qt.CheckStateRole:
return QtGui.QDirModel.data(self, index, role)
else:
if index.column() == 0:
return self.checkState(index)
def flags(self, index):
return QtGui.QDirModel.flags(self, index) | QtCore.Qt.ItemIsUserCheckable
def checkState(self, index):
if index in self.checks:
return self.checks[index]
else:
return QtCore.Qt.Unchecked
def setData(self, index, value, role):
if (role == QtCore.Qt.CheckStateRole and index.column() == 0):
self.checks[index] = value
self.emit(QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), index, index)
return True
return QtGui.QDirModel.setData(self, index, value, role)
#def filtering(self, index):
# self.checks.setFilter(QtCore.QDir.Dirs|QtCore.QDir.NoDotAndDotDot)
class Ui_Dialog(QtGui.QDialog):
def __init__(self,parent=None):
QtGui.QDialog.__init__(self,parent)
self.setObjectName("Dialog")
self.resize(600, 500)
self.llayout = QtGui.QVBoxLayout(parent)
self.model = CheckableDirModel()
self.model.setFilter(QtCore.QDir.Dirs|QtCore.QDir.NoDotAndDotDot)
#self.tree = QtGui.QTreeWidget()
self.tree = QtGui.QTreeView()
self.tree.setModel(self.model)
self.tree.setSortingEnabled(True)
self.tree.setRootIndex(self.model.index(ARGS.filepath))
#self.tree.hideColumn(1)
#self.tree.hideColumn(2)
#self.tree.hideColumn(3)
self.tree.setWindowTitle("Dir View")
self.tree.resize(400, 480)
self.tree.setColumnWidth(0,200)
self.but = QtGui.QPushButton(QtCore.QString("Run"))
self.llayout.addWidget(self.tree)
self.llayout.addWidget(self.but)
self.setLayout(self.llayout)
self.but.clicked.connect(self.print_path)
def print_path(self):
print "hello"
root = self.tree.childCount()
print root
for i in range(root):
print i.text()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
ui = Ui_Dialog()
ui.show()
sys.exit(app.exec_())

If I understand you correctly, what you want is to replace your print_path method with the following:
def print_path(self):
print "hello"
for index,value in self.model.checks.items():
if value.toBool():
print self.model.filePath(index)

Related

Returning a dictionary from a file

I have have written this code defining a class
class OrderRecord:
"""Defines an OrderRecord class, suitable for use in keeping track of order records"""
import tools2
def __init__(self, string):
"""Creates a new OrderRecord object"""
string = string.split(',')
self.date = string[0]
self.location = string[1]
self.name = string[2]
self.colour = string[3]
self.order_num = string[4]
self.cost = 0
def cost_of_order(self):
"""Creates a list of the name and adds up the cost of each letter"""
letter = list(self.name)
for let in letter:
self.cost = self.cost + self.tools2.letter_price(let, self.colour)
return self.cost
def __str__(self):
"""Calls the cost_of_order function and returns the split string in the required format"""
self.cost = self.cost_of_order()
return("Date: {0}\nLocation: {1}\nName: {2}\nColour: \
{3}\nOrder Num: {4}\nCost: {5:.2f}".format(self.date, self.location, \
self.name, self.colour, self.order_num, self.cost))
Now I need to write a function that reads a file containing the following:
20130902,Te Rakipaewhenua,Vinas,parauri,8638
20130909,Te Papaioea,McClary,kikorangi,11643
20131215,Kapiti,Labrie,kikorangi,65291
20141106,Waihopai,Labrie,ma,57910
and returns a dictionary that has the location as the key and lists of OrderRecords as the values.
I know this isn't too hard of a task but I have been stuck on this for awhile because I can't get my head around what to do for it.
Any help would be appreciated.
Maybe something like this. It is not the solution but it has what you need with some modifications.
import collections
dct_result = collections.defaultdict(list)
for line in open('file_path'):
fields = line.split(',')
# index 1 being the second column
dct_result[field(1)].append(OrderRecord( some args ))

Shortest way to get File object from resource in Groovy

Right now I'm using Java API to create file object from resource:
new File(getClass().getResource('/resource.xml').toURI())
Is there any more idiomatic/shorter way to do that in Groovy using GDK?
Depending on what you want to do with the File, there might be a shorter way. Note that URL has GDK methods getText(), eachLine{}, and so on.
Illustration 1:
def file = new File(getClass().getResource('/resource.xml').toURI())
def list1 = []
file.eachLine { list1 << it }
// Groovier:
def list2 = []
getClass().getResource('/resource.xml').eachLine {
list2 << it
}
assert list1 == list2
Illustration 2:
import groovy.xml.*
def xmlSlurper = new XmlSlurper()
def url = getClass().getResource('/resource.xml')
// OP style
def file = new File(url.toURI())
def root1 = xmlSlurper.parseText(file.text)
// Groovier:
def root2 = xmlSlurper.parseText(url.text)
assert root1.text() == root2.text()

Passing values between forms with npyscreen

I am trying to create a simple npyscreen curses application in python that requests user input on one screen, and then verifies it for the user on another screen.
Mostly, this is an effort to understand how values are stored and retrieved from within npyscreen. I am sure I am missing something simple, but I have been unable to find (or understand?) the answer within the documentation.
Sample code below which will not pass the value properly:
#!/usr/bin/env python3.5
import npyscreen as np
class EmployeeForm(np.Form):
def afterEditing(self):
self.parentApp.switchForm('CONFIRMFM')
def create(self):
self.myName = self.add(np.TitleText, name='Name')
self.myDepartment = self.add(np.TitleSelectOne, scroll_exit=True, max_height=3, name='Department', values = ['Department 1', 'Department 2', 'Department 3'])
self.myDate = self.add(np.TitleDateCombo, name='Date Employed')
class EmployeeConfirmForm(np.Form):
def afterEditing(self):
self.parentApp.setNextForm(None)
def create(self):
self.value = None
self.wgName = self.add(np.TitleText, name = "Name:",)
self.wgDept = self.add(np.TitleText, name = "Dept:")
self.wgEmp = self.add(np.TitleText, name = "Employed:")
def beforeEditing(self):
if self.value:
self.name = "Is this correct?"
self.wgName.value = self.myName.value
self.wgDept.value = self.myDepartment.value
self.wgEmp.value = self.myDate.value
def on_cancel(self):
self.parentApp.switchFormPrevious()
class myApp(np.NPSAppManaged):
def onStart(self):
self.addForm('MAIN', EmployeeForm, name='Employee Entry')
self.addForm('CONFIRMFM', EmployeeConfirmForm, name='Employee Confirmation')
if __name__ == '__main__':
TestApp = myApp().run()
I haven't found a straightforward way to directly pass variables between forms. However, you can work around this by using variables that have a global scope among forms.
The NPSAppManaged app class runs completely encapsulated, so if you try to declare global variables at the top of the Python file, the forms within will not have access to them. Instead, declare the variables inside the NPSAppManaged app class before the onStart method as shown below.
class myApp(np.NPSAppManaged):
# declare variables here that have global scope to all your forms
myName, myDepartment, myDate = None, None, None
def onStart(self):
self.addForm('MAIN', EmployeeForm, name='Employee Entry')
self.addForm('CONFIRMFM', EmployeeConfirmForm, name='Employee Confirmation')
if __name__ == '__main__':
TestApp = myApp().run()
You can then access these variables using self.parentApp.[variable name] as follows:
class EmployeeConfirmForm(np.Form):
def afterEditing(self):
self.parentApp.setNextForm(None)
def create(self):
self.add(np.FixedText, value = "Is this correct?")
self.wgName = self.add(np.TitleText, name = "Name:", value = self.parentApp.myName)
self.wgDept = self.add(np.TitleText, name = "Dept:", value = self.parentApp.myDepartment)
self.wgEmp = self.add(np.TitleText, name = "Employed:", value = self.parentApp.myDate)
def on_cancel(self):
self.parentApp.switchFormPrevious()
Note: you don't need to have a separate beforeEditing method since the values will be loaded directly into EmployeeConfirmForm during the create method from the app class global variables.
One way to do this is to use getForm before switchForm to pass the values. The following works for me using python2 to pass the name. Passing other values should be similar. I'm very much learning this myself but please comment if you have further questions.
import npyscreen as np
class EmployeeForm(np.ActionForm):
def create(self):
self.myName = self.add(np.TitleText, name='Name')
self.myDepartment = self.add(np.TitleSelectOne, scroll_exit=True, max_height=3, name='Department', values = ['Department 1', 'Department 2', 'Department 3'])
self.myDate = self.add(np.TitleDateCombo, name='Date Employed')
def afterEditing(self):
self.parentApp.getForm('CONFIRMFM').wgName.value = self.myName.value
self.parentApp.switchForm('CONFIRMFM')
class EmployeeConfirmForm(np.Form):
def afterEditing(self):
self.parentApp.setNextForm(None)
def create(self):
self.value = None
self.wgName = self.add(np.TitleFixedText, name = "Name:",)
self.wgDept = self.add(np.TitleText, name = "Dept:")
self.wgEmp = self.add(np.TitleText, name = "Employed:")
def on_cancel(self):
self.parentApp.switchFormPrevious()
class myApp(np.NPSAppManaged):
def onStart(self):
self.addForm('MAIN', EmployeeForm, name='Employee Entry')
self.addForm('CONFIRMFM', EmployeeConfirmForm, name='Employee Confirmation')
if __name__ == '__main__':
TestApp = myApp().run()
Assign values (including the value returned by addForm) to self.whatever.
So if you do
self.myAppValue = 2
self.mainForm = self.addForm('MAIN', MainForm, ...)
self.form2 = self.addForm('FORM2', Form2, ...)
you can use these in any form
self.parentApp.myAppValue
self.parentApp.mainForm.main_form_widget.main_form_value
And in myApp() you can do
self.mainForm.main_form_widget.main_form_value
I had the same problems during development as the documentation is not very detailed about passing values between forms.
I have added a few modification, the first one was changing Form to ActionForm in the confirmation form to have access to ok and cancel buttons. Secondly, the values on the confirmation form should not be editable as this is a confirmation. You can press cancel to edit on the previous form. The last one was passing the first element of the department list rather than the value - it would be just a list index. I hope it helps a little.
#!/usr/bin/env python3.5
import npyscreen as np
class EmployeeForm(np.Form):
def create(self):
self.myName = self.add(np.TitleText, name='Name')
self.myDepartment = self.add(np.TitleSelectOne, scroll_exit=True, max_height=3, name='Department', values = ['Department 1', 'Department 2', 'Department 3'])
self.myDate = self.add(np.TitleDateCombo, name='Date Employed')
def afterEditing(self):
self.parentApp.switchForm('CONFIRMFM')
self.parentApp.getForm('CONFIRMFM').wgName.value = self.myName.value
self.parentApp.getForm('CONFIRMFM').wgDept.value = self.myDepartment.values[0]
self.parentApp.getForm('CONFIRMFM').wgEmp.value = self.myDate.value
class EmployeeConfirmForm(np.ActionForm):
def create(self):
self.add(np.FixedText, value="Is this correct?", editable=False)
self.wgName = self.add(np.TitleText, name = "Name:", editable=False)
self.wgDept = self.add(np.TitleText, name = "Dept:", editable=False)
self.wgEmp = self.add(np.TitleText, name = "Employed:", editable=False)
def on_ok(self):
self.parentApp.setNextForm(None)
def on_cancel(self):
self.parentApp.switchFormPrevious()
class myApp(np.NPSAppManaged):
def onStart(self):
self.addForm('MAIN', EmployeeForm, name='Employee Entry')
self.addForm('CONFIRMFM', EmployeeConfirmForm, name='Employee Confirmation')
if __name__ == '__main__':
TestApp = myApp().run()

How to move an image with keyboard in Kivy?

I am simply trying to move an image from left to right using the keyboard keys. I tried making a class called movableImage that inherits from Image. I think this is where I did something wrong, specifically the init function. When I run the code below I am getting AttributeError: 'function' object has no attribute 'widget' on line 16. What am I doing wrong here?
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.input.motionevent import MotionEvent
from kivy.core.window import Window
class character(Widget):
pass
class moveableImage(Image):
def __init__(self, **kwargs):
super(moveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard
if self._keyboard.widget:
# If it exists, this widget is a VKeyboard object which you can use
# to change the keyboard layout.
pass
self._keyboard.bind(on_key_down=self._on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
print keycode #move littleguy to the left
elif keycode[1] == 'right':
print keycode #move littleguy to the right
return True
littleguy = moveableImage(source='selectionscreen/littleguy.zip', anim_available=True, anim_delay=.15)
class gameApp(App):
def build(self):
m = character()
m.add_widget(littleguy)
return m
if __name__ == '__main__':
gameApp().run()
I should also add that I HAVE read the Kivy keyboardlistener example and I am still stuck.
Here's a working example of what you're trying to do, just run it and use the right / left arrow keys to move it right / left:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
class character(Widget):
pass
class MoveableImage(Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.x -= 10
elif keycode[1] == 'right':
self.x += 10
else:
return False
return True
class gameApp(App):
def build(self):
wimg = MoveableImage(source='tools/theming/defaulttheme/slider_cursor.png')
m = character()
m.add_widget(wimg)
return m
if __name__ == '__main__':
gameApp().run()
The problem you ran into, is that request_keyboard is a function, and needs to be called that way. You can also remove the if self._keyboard.widget: part.

bulk update/delete entities of different kind in db.run_in_transaction

Here goes pseudo code of bulk update/delete entities of different kind in single transaction. Note that Album and Song entities have AlbumGroup as root entity. (i.e. has same parent entity)
class Album:
pass
class Song:
album = db.ReferenceProperty(reference_class=Album,collection_name="songs")
def bulk_update_album_group(album):
updated = [album]
deleted = []
for song in album.songs:
if song.is_updated:
updated.append(song)
if song.is_deleted:
deleted.append(song)
db.put(updated)
db.delete(deleted)
a = Album.all().filter("...").get()
# bulk update/delete album.
db.run_in_transaction(bulk_update_album,a)
But I met a famous "Only Ancestor Queries in Transactions" error at the iterating back-reference properties like "album.songs". I guess ancestor() filter does not help because those entities are modified in memory.
So I modify example like this: prepare all updated/deleted entities before calling transaction.
def bulk_update_album2(album):
updated = [album]
deleted = []
for song in album.songs:
if song.is_updated:
updated.append(song)
if song.is_deleted:
deleted.append(song)
def txn(updated,deleted):
db.put(updated)
db.delete(deleted)
db.run_in_transaction(txn,updated,deleted)
Now I found that iterating back-reference property force reload existing entities. So re-iterating back-reference property after modifying should be avoided!!
All I want to verify is:
When need to bulk update/delete many entities of different kind,
is there any good coding pattern for this situation?
my last code can be good one?
Here goes full code example:
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
import logging
from google.appengine.ext import db
class Album(db.Model):
name = db.StringProperty()
def __repr__(self):
return "%s%s"%(self.name,[song for song in self.songs])
class Song(db.Model):
album = db.ReferenceProperty(reference_class=Album,collection_name='songs')
name = db.StringProperty()
playcount = db.IntegerProperty(default=0)
def __repr__(self):
return "%s(%d)"%(self.name,self.playcount)
def create_album(name):
album = Album(name=name)
album.put()
for i in range(0,5):
song = Song(parent=album, album=album, name='song#%d'%i)
song.put()
return album
def play_all_songs(album):
logging.info(album)
# play all songs
for song in album.songs:
song.playcount += 1
logging.info(song)
# play count also 0 here
logging.info(album)
def save_play_count(album):
updated = []
for song in album.songs:
updated.append(song)
db.put(updated)
db.run_in_transaction(save_play_count,album)
def play_all_songs2(album):
logging.info("loading : %s"%album)
# play all songs
updated = []
for song in album.songs:
song.playcount += 1
updated.append(song)
logging.info("updated: %s"%updated)
db.put(updated)
logging.info("after save: %s"%album)
def play_all_songs3(album):
logging.info("loading : %s"%album)
# play all songs
updated = []
for song in album.songs:
song.playcount += 1
updated.append(song)
# reload
for song in album.songs:
pass
logging.info("updated: %s"%updated)
def bulk_save_play_count(updated):
db.put(updated)
db.run_in_transaction(bulk_save_play_count,updated)
logging.info("after save: %s"%album)
class MainHandler(webapp.RequestHandler):
def get(self):
self.response.out.write('Hello world!')
album = Album.all().filter('name =','test').get()
if not album:
album = db.run_in_transaction(create_album,'test')
# BadRequestError: Only ancestor queries are allowed inside transactions.
#play_all_songs(album)
# ok
#play_all_songs2(album)
play_all_songs3(album)
def main():
application = webapp.WSGIApplication([('/', MainHandler)],
debug=True)
util.run_wsgi_app(application)
if __name__ == '__main__':
main()
Please note the the ReferenceProperty is not enough to put the entities in the same group. When you create a Song model you should pass a parent argument with the model's parent (e.g., the Album).
It looks like this:
album = Album.all().filter("...").get()
new_song = Song(name='Seven Nation Army', parent=album)
new_song.save()
See the documentation about ancestors.

Resources