I'm trying to do some basic Qt file manager app in Python 3.6 with PySide2. Code is like this:
class MainWidget(QWidget):
startDir = "."
def __init__(self):
super().__init__()
isDirselectDone = self.selectContentDir()
if isDirselectDone:
self.model = QFileSystemModel()
self.model.setRootPath(self.startDir)
self.tree = QTreeView()
self.tree.setModel(self.model)
self.tree.setSortingEnabled(True)
self.tree.show()
def selectContentDir(self):
print("Selecing game content folder")
self.startDir = QFileDialog.getExistingDirectory()
if(len(self.startDir) == 0):
print("Game content folder loading cancelled")
return False
print("Trying to load ", self.startDir)
return True
My problem is that no matter what is the contents of the chosen directory, the view does not sort the files. I can click oh the headers, and the little arrows are changing, but everything remains in the order it was loaded.
I tried to look for solutions, but the answers either say that you just have to call the setSortingEnabled() and everything magically works (which is not the case), or they describe some voodoo magic rituals involving inheriting from QAbstractTreeSuperAncientGodItemViewDelegate, then re-implement half of the Qt library and finally creating a Tartarus-like maze by connecting slots and signals all over the place.
So what is the easiest / simplest way to make this sorting work according to latest Qt standards?
I found a solution for my case, based on the following assumptions:
These three lines:
model.setRootPath(directory)
tree.setRootIndex(self.model.index(directory))
tree.setSortingEnabled(True)
Seem they have to be in this specific order, and of course the model rootpath and the tree root index has to point to the same directory (during debugging I tried to set them to different ones, just to see what happens when the tree shows just a subset of the model data, but as expected it broke multiple things in the app).
Also, any custom lines (like handling your custom columns) has to happen between the root index setting, and the sorting enable. I don't know if this is really a general rule, it seems kind of arbitrary, but in my project it turned out to be crucial to call setSortingEnabled() as a last step, to make it work.
If your custom columns do not contain simple text (or anything not easily sortable, in my case a combobox) or they are hidden, you'd better exclude that column from the sorting. This is not mandatory, but for me it resulted in faster response time for the other columns.
Related
I'm getting very confused trying to setup my simulation correctly in PyDrake. What I want is to have an actuated robot (with e.g. an InverseDynamicsController on it) together with an object in the scene that the robot will manipulate. However, I'm struggling to sort out how to create and use the MultibodyPlant, SceneGraph, Context, Simulator combination correctly.
Here is roughly what I've tried to do:
builder = DiagramBuilder()
plant, scene_graph = AddMultibodyPlantSceneGraph(builder, time_step=1e-4)
parser = Parser(plant, scene_graph)
# Add my robot
robot = parser.AddModelFromFile(robot_urdf)
robot_base = plant.GetFrameByName('robot_base')
plant.WeldFrames(plant.world_frame(), robot_base)
# Add my object
parser.AddModelFromFile(FindResourceOrThrow("drake/my_object.urdf"))
plant.finalize()
# Add my controller
Kp = np.full(6, 100)
Ki = 2 * np.sqrt(Kp)
Kd = np.full(6, 1)
controller = builder.AddSystem(InverseDynamicsController(plant, Kp, Ki, Kd, False))
controller.set_name("sim_controller");
builder.Connect(plant.get_state_output_port(robot),
controller.get_input_port_estimated_state())
builder.Connect(controller.get_output_port_control(),
plant.get_actuation_input_port())
# Get the diagram, simulator, and contexts
diagram = builder.Build()
simulator = Simulator(diagram)
context = simulator.get_mutable_context()
plant_context = plant.GetMyContextFromRoot(context)
However, this has some undesirable qualities. First, as long as I've added the object, then I get this error:
Failure at systems/controllers/inverse_dynamics_controller.cc:32 in SetUp(): condition 'num_positions == dim' failed.
Second, with the object added, the object pose becomes part of my InverseKinematics problem, and when I do SetPositions with plant_context, I have to set both my arm joints AND the pose of the object, when I feel like I should only be setting the robot's joint positions with SetPositions.
I realize I've done something wrong with this setup, and I'm just wondering what is the correct way to have an instance of Simulator that I can run simulations with that has both an actuated robot, and a manipulable object? Am I supposed to create multiple plants? Multiple contexts? Who shares what with who?
I'd really appreciate some advice on this, or a pointer to an example. Drake is great, but I struggle to find minimal examples that do what I want.
Yes, you can add a separate MultibodyPlant for control. See https://github.com/RobotLocomotion/drake/blob/master/examples/planar_gripper/planar_gripper_simulation.cc for an example. The setup is similar to yours, though it's in C++. You can try mimicking the way the diagram is wired up there.
When you do have two plants, you want to call SetPositions on the simulation plant (not the control plant). You can set only the robot positions by using ModelInstanceIndex.
# Add my robot
robot = parser.AddModelFromFile(robot_urdf)
...
plant.SetPositions(plant_context, robot, robot_positions)
The company I work at requires a list of all inaccessible images/shapes in a .pptx document (don't have alt-text and aren't decorative). To automate the process, I'm writing a script that extracts all inaccessible images/shapes in a specified .pptx and compiles a list. So far, I've managed to make it print out the name, slide #, and image blob of images with no alt-text.
Unfortunately after extensively searching the docs, I came to find that the python-pptx package does not support functionality for checking whether an image/shape is decorative or not.
I haven't mapped XML elements to objects in the past and was wondering how I could go about making a function that reads the val attribute within the adec:decorative element in this .pptx file (see line 4).
<p:cNvPr id="3" name="Picture 2">
<a:extLst>
<a:ext uri="{FF2B5EF4-FFF2-40B4-BE49-F238E27FC236}"><a16:creationId xmlns:a16="http://schemas.microsoft.com/office/drawing/2014/main" id="{77922398-FA3E-426B-895D-97239096AD1F}" /></a:ext>
<a:ext uri="{C183D7F6-B498-43B3-948B-1728B52AA6E4}"><adec:decorative xmlns:adec="http://schemas.microsoft.com/office/drawing/2017/decorative" val="0" /></a:ext>
</a:extLst>
</p:cNvPr>
Since I've only recently started using this package, I'm not sure how to go about creating custom element classes within python-pptx. If anyone has any other workaround or suggestions please let me know, thank you!
Creating a custom element class would certainly work, but I would regard it as an extreme method (think bazooka for killing mosquitos) :).
I'd be inclined to think you could accomplish what you want with an XPath query on the closest ancestor you can get to with python-pptx.
Something like this would be in the right direction:
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative")
if adec_decoratives:
print("got one, probably need to look more closely at them")
One of the challenges is likely to be getting the adec namespace prefix registered because I don't think it is by default. So you probably need to execute this code before the XPath expression, possibly before loading the first document:
from pptx.oxml.ns import _nsmap
_nsmap["adec"] = "http://schemas.microsoft.com/office/drawing/2017/decorative"]
Also, if you research XPath a bit, I think you'll actually be able to query on <adec:decorative> elements that have val=0 or whatever specific attribute state satisfies what you're looking for.
But this is the direction I recommend. Maybe you can post your results once you've worked them out in case someone else faces the same problem later.
The problem was a lot simpler after all! All thanks too #scanny I was able to fix the issue and target the val=1 attribute in the adec:decorative element. The following function returns True if val=1 for that shape.
def isDecorative(shape):
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative[#val='1']")
if adec_decoratives:
return True
Here is the complete script for checking accessibility in a single specified .pptx so far (Prints out image name and slide # if image is not decorative and doesn't have alt-text):
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.enum.shapes import PP_PLACEHOLDER
from pptx.oxml.ns import _nsmap
_nsmap["adec"] = "http://schemas.microsoft.com/office/drawing/2017/decorative"
filePath = input("Specify PPT file path > ")
print()
def validShape(shape):
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
return True
elif shape.shape_type == MSO_SHAPE_TYPE.PLACEHOLDER:
if shape.placeholder_format.type == PP_PLACEHOLDER.OBJECT:
return True
else:
return False
else:
return False
def isDecorative(shape):
cNvPr = shape._element._nvXxPr.cNvPr
adec_decoratives = cNvPr.xpath(".//adec:decorative[#val='1']")
if adec_decoratives:
return True
# Note: References custom #property added to shared.py and base.py
def hasAltText(shape):
if shape.alt_text:
return True
def checkAccessibility(prs):
for slide in prs.slides:
for shape in slide.shapes:
if validShape(shape) and not isDecorative(shape) and not hasAltText(shape):
yield shape
slideNumber = prs.slides.index(slide) + 1
print("Slide #: %d " % slideNumber + "\n");
for picture in checkAccessibility(Presentation(filePath)):
print(picture.name);
I would like to create a VIM insert-mode-completion popup menu, preferably directly via the python vim module but also by calling vim commands if necessary. Per my requirements, if this is possible, what do I need to know?
Requirements
Modify the menu based on input. Either recolor and replace select characters ala easymotion plugin, or completely replace content, possibly resulting in a change of size.
Customizable navigation bindings, example:
j/k for vertical navigation (partial redraw)
h/l for category navigation/refinement (full redraw)
others as category/relationship shortcuts (full)
others as source cycling (full)
easymotion-style bindings (partial)
others for related functionality (none)
optionally, in lieu of the above bindings, a fuzzy filtering mode (capture all input) (full)
Hook to run action when menu is destroyed
Ability to replace previous word if menu item selected (easily done in normal mode... but, is there a better approach than calling :norm?)
Once again, I need to know if any of this is possible. If so, please provide specific documentation regarding the required capabilities, APIs, or functions. Well, enough to get me started.
If important, I'm not sure of the interface specifics yet but the menu itself may need to be quite large to accommodate the content.
Edit:
I haven't tried anything; rather I'm asking what I should read or know to implement the vim-specific functionality I need. All I now have is python code that accepts a sentence and a word in that sentence, determines the POS, lemmatises the word, and provides synonyms.
It should be clear by now this is a vim plugin providing thesaurus-like functionality, augmenting vim's built-in CTRL_X-CTRL_T functionality. Unfortunately synonymy is a complicated hierarchy, for example see thesaurus.com or wordnet. Below is a tree of the synonym selection process. To provide useful thesaurus functionality I would need to navigate this tree within the insert-mode-completion popup menu. By automatically inferring the POS the first step can be skipped, and of course it makes sense to initially merge and display all sense synonyms irrespective of relationship. However, to determine the POS I need access to the entire sentence, and I still need to be able to navigate a sense selection menu. I also want to be able to provide scratch buffer detailing word definitions and example sentences for the currently highlighted popup menu entry. Hence the necessity for a hook; to destroy the buffer when the menu is destroyed. All the other keybindings I've described would be conveniences to, for example, filter by relationship, open the informational scratch buffer, or switch POS.
POS Sense Relationship Synonym
N -> Sense 1 -> Relationship 1 -> Synonym 1
Synonym 2
...
Synonym n
-> Relationship 2 -> Synonym 1
...
Synonym n
-> Relationship 3 -> Synonym 1
...
Synonym n
Sense 2 -> Relationship 1 -> ...
Sense 3 -> Relationship 2 -> ...
V -> Sense 1 -> ...
A -> ...
Insert completion popup menus are great because they preserve context: surrounding text doesn't change, remains (mostly) visible, and windows aren't resized. I could provide the functionality I need in a separate buffer (such as a unite plugin), however I'd rather not.
After reading :h complete-functions:
If refresh="alway", complete-functions will be re-invoked each time leading text is changed. The purpose is to refine the matches, however this has little meaning for synonym-matching, where the word is already complete and instead will just be replaced. Aside from this, insert-completion popup menus only provide minimal key mappings: <CTRL-H>, CTRL-L>, <CTRL-Y>, <CTRL-E>, etc. Additional mappings can be added using pumvisible(), however such mappings affect all popup menus, and so would not be applicable. Of course I could use <expr> to check a global variable such as g:popup-menu-is-thesaurus, but this approach is basically a heap of hacks. For example, to display a new category in the menu, I could do something like:
:call Thesaurus#BindKey("h","w:Thesaurus#CategoryUp")
:call Thesaurus#BindKey("i","w:Thesaurus#InsertMode")
with:
function! Thesaurus#BindKey(key, function)
inoremap <expr> a:key a:function
endfunction
function! Thesaurus#CategoryUp()
if !b:popup-menu-is-thesaurus
return v:char
let b:thesaurus-category-index -= 1
endfunction
function! Thesaurus#InsertMode()
if !b:popup-menu-is-thesaurus
return v:char
let b:thesaurus-mode = "insert"
endfunction
function! Thesaurus#CompleteFunc(findstart, base)
if a:findstart
...
else
if b:thesaurus-mode = "insert"
return Thesaurus#FuzzyMatch(base)
else
return Thesaurus#Redraw()
endif
endif
endfunction
function! Thesaurus#Redraw()
...
endfunction
* Obviously I'm not very good with VimL. Also, am I using v:char correctly?
Of course I have no idea how to replace the previous word once an entry is selected, since the only way to enable fuzzy matching is to have a:base be empty.
Edit2: And how in the world do I get my completion-function triggered, preferably via the standard thesaurus-style completion shortcut, i_CTRL-X_CTRL-T? I don't want to lose my custom completions (omni and user-defined completion), and since the popup displays in the current buffer, unlike FuzzyFinder I can't override omnifunc.
Perhaps the ideal approach would be to have full control of the menu-drawing functionality to build the popup from scratch, and fake a new insert-completion popup menu mode using plugins such as tinymode, tinykeymap or submode.
Please keep in mind that the insert-mode completion popup menu is for completing matches e.g. offering foobar and foomatic when you type foo and trigger completion. There is no generic insert-mode menu with arbitrary actions, and it's probably a bad idea to implement such. That said, some plugins (e.g. FuzzyFinder) mis-use insert-mode completion menus for a dynamic choice selector (in a scratch buffer, so what get's completed is discarded there).
You'll find the full specification and an example at :help complete-function. If that doesn't satisfy you / leaves open questions, that's a sure sign that you're trying to use it for something it wasn't meant for.
Modify the menu based on input.
With each typed key, your 'completefunc' will be re-invoked, and it can offer a (reduced) set of matches.
Customizable navigation bindings
Bad idea. The user should customize this for all completions (using :imap <expr> with pumvisible() conditionals).
Hook to run action when menu is destroyed
The CompleteDone event has been added in recent Vim versions, but usually the only action should be "insert the match", which gets done automatically.
Ability to replace previous word if menu item selected
On the first invocation of your 'completefunc', your function can specify the base column, i.e. where the completion matches will start.
Asking around a different way of doing this.
I am trying to look at the screen, decide if an image exists (from a list) and choose any that are there, then click "go". If none of the list items are there, it would execute click("go.png") and carry on. If there are any list items there, it clicks it and then executes the click("go.png")
wait("start.png", 10)
click("start.png")
class gameOne():
def pickone():
imageFile = ["one.png", "two.png", "three.png"]
if exists(imageFile):
click(imageFile)
click("go.png")
With this, the click("start.png") and click("go.png") work. It seems to just skips the class. No error is given.
You aren't using the class correctly, I'm not sure how you are expecting this to work, but you don't need that for what you're doing:
wait("start.png", 10)
click("start.png")
imageFile = ["one.png", "two.png", "three.png"]
if exists(imageFile):
click(imageFile)
click("go.png")
This should work as intended.
I'm working on a python application that runs on 2 different platforms, namely regular desktop linux and Maemo 4. We use PyGTK on both platforms but on Maemo there are a bunch of little tweaks to make it look nice which are implemented as follows:
if util.platform.MAEMO:
# do something fancy for maemo
else:
# regular pygtk
There are roughly 15 of these if statements needed to get the UI looking and working nice on Maemo 4.
This has been very manageable for all this time. The problem is that a while ago there was a new version of Maemo released (5, aka fremantle) and it has some big differences compared to Maemo 4. I don't want to add a bunch of checks throughout the GUI code in order to get all 3 platforms working nicely with the same codebase because that would get messy. I also don't want to create a copy of the original GUI code for each platform and simply modify it for the specific platform (I'd like to re-use as much code as possible).
So, what are ways to have slightly different UIs for different platforms which are based on the same core UI code? I don't think this is a python or Maemo-specific question, I'd just like to know how this is done.
You could wind up much of this in a factory:
def createSpec():
if util.platform.MAEMO: return Maemo4Spec()
elif util.platform.MAEMO5: return Maemo5Spec()
return StandardPyGTKSpec()
Then, somewhere early in your code, you just call that factory:
spec = createSpec()
Now, everywhere else you had conditions, you just call the necessary function:
spec.drawComboBox()
As long as drawComboBox(), handles anything specific to the platform, you should be in good shape.
You could isolate the platform specific stuff you need to do into small consistently named functions inside a platform module, create the right function name using the platform you're running on and then getattr the right one and call it. The if/else boilerplate would disappear then.
I've made a separate module to handle all of my specializing between normal Linux, Maemo 4.1, and Maemo 5. It detects what features are available and allows the program to gracefully degrade.
For example
def _fremantle_hildonize_window(app, window):
oldWindow = window
newWindow = hildon.StackableWindow()
oldWindow.get_child().reparent(newWindow)
app.add_window(newWindow)
return newWindow
def _hildon_hildonize_window(app, window):
oldWindow = window
newWindow = hildon.Window()
oldWindow.get_child().reparent(newWindow)
app.add_window(newWindow)
return newWindow
def _null_hildonize_window(app, window):
return window
try:
hildon.StackableWindow
hildonize_window = _fremantle_hildonize_window
except AttributeError:
try:
hildon.Window
hildonize_window = _hildon_hildonize_window
except AttributeError:
hildonize_window = _null_hildonize_window
For more, see
Dialcentral, Gonert, ejpi, or Quicknote's source code for a file called hildonize.py
https://garage.maemo.org/plugins/ggit/browse.php/?p=gc-dialer;a=blob;f=src/hildonize.py;
Another example from The One Ring's GObject Utils (go_utils.py)
def _old_timeout_add_seconds(timeout, callback):
return gobject.timeout_add(timeout * 1000, callback)
def _timeout_add_seconds(timeout, callback):
return gobject.timeout_add_seconds(timeout, callback)
try:
gobject.timeout_add_seconds
timeout_add_seconds = _timeout_add_seconds
except AttributeError:
timeout_add_seconds = _old_timeout_add_seconds