Python and Qt : Retrieving branch names in multi-leveled QMenu - qt

Having trouble finalizing a dynamic QMenu tree.
The structure and format is perfect, but what remains missing is the return of all branch names when triggering the end-action.
The only implement I have tried with ANY trend toward a solution is the use of self.sender(); which returns only the name of the end-action.
Before adding a ton of the lengthy code snips - starting by conceptualizing the question seemed best in case there is some (obvious) means I am over-looking.
Example;
The ideal return based on the footer figure would be something along the lines of...
Top Image:
'Single Results' - 'Head Results'
Middle Image:
'Batch Results' - 'testBatch_vr3' - 'Run-1' - 'Budget Results'
Bottom Image:
'Single Results' - 'testBatch_vr3' - 'Run-3' - 'Particle Tracks'
To the point;
How can all names in a multi-leveled set of QMenus be retrieved when triggering end-action?

The following complex bits resolved my problem. It might be a bit obscure way to go about it (hovered signal from menu to search for dictionary menu entry) - but it works well for now.
# checks batch processing folder for existing directories and publishes the contents
# into the batch results menu comboBox
def populateBatchResults(self):
self.batchMenuDict = {}
self.runMenuDict = {}
self.runBatchResultsPopup.clear()
self.batchDirNamesMenu.clear()
batchModDir = self.estabBatchModelDir()
for batch in os.listdir(batchModDir):
fullBatchDir = batchModDir+str(batch)
if os.path.isdir(fullBatchDir):
self.batchMenuDict[batch] = QMenu(self.iface.mainWindow())
self.batchMenuDict[batch].setTitle(str(batch))
self.runBatchResultsPopup.addMenu(self.batchMenuDict[batch])
for run in os.listdir(fullBatchDir):
fullRunDir = fullBatchDir+'\\'+str(run)
if os.path.isdir(fullRunDir):
self.runMenuDict[run] = QMenu(self.iface.mainWindow())
self.runMenuDict[run].setTitle(str(run))
self.batchMenuDict[batch].addMenu(self.runMenuDict[run])
self.runMenuDict[run].hovered.connect(self.assertBatchMenuSelection)
# get all current cursor hovered menu names
def assertBatchMenuSelection(self):
self.selectedBatch = self.runBatchResultsPopup.activeAction().text()
self.selectedRun = self.batchMenuDict.get(self.selectedBatch).activeAction().text()
self.selectedAction = self.runMenuDict.get(self.selectedRun).activeAction().text()

Related

Function for Google Sheets' Script editor with a button for TODAY(), and NOW() in two different columns of which are the next not blank in the column

Currently, I'm looking at some simple documentation for vague ways to make a 'button' (image) over a Google sheet to trigger a function on the script editor. I'm not familiar with this type of Syntax, I typically do AutoHotKey, and a bit of python.
All I want to do is have this button populate 2 columns. The current date in one, and the current time in the other (It doesn't even have to have its year or the seconds tbh). I don't know if it matters of what the pages name is based on how the script works. So the range is ( 'Log'!G4:H ).
Like if I were to make it for AutoHotkey I would put it as :
WinGet, winid ,, A ; <-- need to identify window A = active
MsgBox, winid=%winid%
;do some stuff
WinActivate ahk_id %winid%
So it affects any page it's active on.
I would like to use the same function on the same columns across different sheets. Ideally, that is. I don't care if I have to clone each a unique function based on the page, but I just can't even grasp this first step, lol.
I'm not too familiar with this new macro. If I use this macro does it only work for my client, because of say like it recording relative aspect ratio movements?
IE if I record a macro on my PC, and play it on my android. Will the change in the platform change its execution?
If anyone can point me in any direction as to any good documentation or resources for the Google Sheet Script Editor or its syntaxes I would really appreciate it.
EDIT: Just to clarify. Im really focused in on it being a function that populates from a click/press(mobile) of an image. I currently use an onEDIT on the sheet, and it wouldnt serve the purposes that I want for this function. Its just a shortcut to quickly input a timestamp, and those fields can still be retouched without it just reapplying a new function for a newer current time/date.
EDIT:EDIT: Ended up with a image button that runs a script that can only input to the current cell.
function timeStamp() {
SpreadsheetApp.getActiveSheet()
.getActiveCell()
.setValue(new Date());
}
It only works on the cell targeted.
I would like to force the input in the next availible cell in the column, and split the date from the time, and put them into cells adjacent from one another.
maybe this will help... if the 1st column is edited it will auto-print date in 2nd column and time in 3rd column on Sheet1:
function onEdit(e) {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Sheet1" ) {
var r = s.getActiveCell();
if( r.getColumn() == 1 ) {
var nextCell = r.offset(0, 1);
var newDate = Utilities.formatDate(new Date(),
"GMT+8", "MM/dd/yyyy");
nextCell.setValue(newDate);
}
if( r.getColumn() == 1 ) {
var nextCell = r.offset(0, 2);
var newDate1 = Utilities.formatDate(new Date(),
"GMT+8", "hh:mm:ss");
nextCell.setValue(newDate1);
}}}
https://webapps.stackexchange.com/a/130253/186471

SciTE Script - How to get inside a Tree Control to set checkboxes

I'm using AutoIt and SciTE to create an installation script. The problem I am running into is that there is a tree menu for selection of features. I can select the whole treeview (SysTreeView32), but am not sure how to get inside it to check the boxes without doing a mouse move and click (not a great option).
The Treeview looks like this:
The Control Info from AutoIT is like this:
I'm sure it is possible, just can't figure out how to do it. This is my first attempt a such a script. Creating a response file does not work for this exe for some reason. So - this appears to be my only way out to create a somewhat silent install (not silent anymore, but at least automated).
* EDIT - Current State of Things *
I did figure out how to do some of this, but I still can't figure out if the items is selected before accessing it. So - since it toggles, I could be turning off a feature I want!
$hWnd = WinWaitActive($WindowTitle, 'Select Features')
$tvCtl = ControlGetHandle($WindowTitle, '', 'SysTreeView321')
$firstItem = _GUICtrlTreeView_FindItem($tvCtl, 'eBooks')
_GUICtrlTreeView_SelectItem($tvCtl, $firstItem, $TVGN_FIRSTVISIBLE)
_GUICtrlTreeView_ClickItem($tvCtl, $firstItem, "left", True, 1)
Send('{SPACE}')
I wouldn't think I would have to send the space since I sent the ClickItem, but seems so.
I could also do this:
ControlTreeView($hWnd, '', $tvCtl, 'Select', '#0')
ControlSend($hWnd, '', $tvCtl, ' ')
That will toggle the first one. So - i can count them all up and do it that way.
But when I check for "IsEnabled" or "IsChecked", it always says NO. So - I can't check the ones I need only. I have to hope their status is what I expect.
Here is how I am checking "IsChecked" and "IsEnabled":
If ControlCommand($hWnd, '', $logTool, 'IsEnabled') then
ConsoleWrite('Log Tool - IsEnabled' & #CRLF)
Else
ConsoleWrite('Log Tool - NOTEnabled' & #CRLF)
EndIf
and
If ControlCommand($hWnd, '', $logTool, 'IsChecked') then
ConsoleWrite('Log Tool - IsChecked' & #CRLF)
Else
ConsoleWrite('Log Tool - NOTChecked' & #CRLF)
EndIf
It always comes back NOTEnabled and NOTChecked. I made sure that I ran the same procedure above: FindItem, SelectItem, ClickItem. And, the correct item is highlighted/selected when this procedure is run - I can see that. So - it just isn't returning a proper value.
Opt('WinTitleMatchMode', 2)
$hWnd = WinGetHandle("InstallShield Wizard") ; Notice the correct title
$hTree = ControlGetHandle($hWnd, '', "[CLASS:SysTreeView32;INSTANCE:1]")
; == Now you can interact with the treeview with functions from "GuiTreeView.au3"
EDIT:
Try this
; Select the item so:
_GUICtrlTreeView_SelectItem($hTree, $hItem, $TVGN_CARET)
; Get checked state:
_GUICtrlTreeView_GetChecked($hTree, $hItem)
For more deatails read the AutoIt help.

"Down arrow" moves cursor to end of line - how to turn it off

In IPython Notebook / Jupyter, arrow up/down keystrokes within a cell are handled by CodeMirror (as far as I can tell). I use these actions a lot (re-bound to control-p / control-n) to move between cells; but at the end of every cell, the cursor moves to end of line first before jumping to the next cell. This is counter-intuitive and, to me, rather distracting.
Is there any way to configure CodeMirror to make this move down to be just that - a move down?
Thanks!
The moving-to-next-cell behavior is defined by IPython wrapper code, which probably checks whether the cursor is at the end of the current cell, and overrides the default CodeMirror behavior in that case. You'll have to find that handler and somehow replace it with one that checks whether the cursor is on the last line. (I don't know much about IPython, only about CodeMirror, so I can't point you at the proper way to find and override the relevant code. They might have bound the Down key, or they might have overridden the goLineDown command.)
Knowing that I wasn't alone in wanting to skip the "going to end of line" behavior when going down from the last line of a code cell, I investigated that behavior and found out that:
it's CodeMirror that goes to the end of line when you type down in the last line of a code cell (file: codemirror.js ; "methods": findPosV and moveV)
and it's IPython that decides what to do with the "down" event after it has been handled by CodeMirror (file: cell.js ; class: Cell ; method: handle_codemirror_keyevent) ; looking at the code, I saw that IPython ignores the event when not at the last character of the last line.
This essentially confirms Marijin's answer.
The primary goal being to jump to the next cell, I think there's no need to prevent CodeMirror from going to the end of that line. The point is to force IPython to handle the event anyway.
My solution was to change the code from Cell.prototype.handle_codemirror_keyevent to this:
Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
var shortcuts = this.keyboard_manager.edit_shortcuts;
var cur = editor.getCursor();
if((cur.line !== 0) && event.keyCode === 38){
// going up, but not from the first line
// don't do anything more with the event
event._ipkmIgnore = true;
}
var nLastLine = editor.lastLine();
if ((event.keyCode === 40) &&
((cur.line !== nLastLine))
) {
// going down, but not from the last line
// don't do anything more with the event
event._ipkmIgnore = true;
}
// if this is an edit_shortcuts shortcut, the global keyboard/shortcut
// manager will handle it
if (shortcuts.handles(event)) {
return true;
}
return false;
};
This code provides the desired behavior for the "down-arrow" key (almost: the cursor still goes to the end of the line, except that we don't see it, as we're already in another cell at that point), and also handles the "up-arrow" key similarly.
To modify the handle_codemirror_keyevent prototype, you have two possibilities:
You edit the cell.js file and change the code of the prototype to the code I gave above. The file is in <python>/Lib/site-packages/IPython/html/static/notebook/js or something similar depending on you distro
Much better, after the page is loaded, you change that prototype dynamically by doing this:
IPython.Cell.prototype.handle_codemirror_keyevent = function (editor, event) {
<same code as above>
};
You can do that in your custom.js for example, or create an extension to do it (that's what I did).

Python/Tkinter How to update information in grid

I'm running Python 3.2.2 and writing some code to test sockets. For the ease of testing, I'm using Tkinter to add a GUI interface. What I have yet to figure out is how to update the information in the grid I'm using. I want to update "host2" and "port2" in the functions "change1" and "change3" in the following code:
import socket
from tkinter import *
import tkinter.simpledialog
root = Tk()
root.title("Server")
root.iconbitmap("etc.ico")
root.geometry("350x100+200+200")
frame = Frame(root)
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
port1 = Label(frame,text="Port: ").grid(row=1,column=0)
HOST = 'localhost'
PORT = 11111
STATUS = 'EMPTY'
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
port2 = Label(frame,text=PORT,width=10).grid(row=1,column=1)
status1 = Label(root,text=STATUS)
status1.pack(side=RIGHT,padx=2,pady=2)
def change1():
global HOST
HOST= tkinter.simpledialog.askstring(title="Host",prompt="Enter the IP of the Host.")
host2.grid_forget()
def change3():
global PORT
PORT= tkinter.simpledialog.askinteger(title="Port",prompt="Enter the Port of the IP.")
port2.grid_forget()
def go1():
global HOST
global PORT
home = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
home.bind((HOST, PORT))
home.listen(1)
conn, addr = home.accept()
print (addr)
while 1:
data = conn.recv(1024)
if not data: break
global STATUS
STATUS = data.decode('UTF-8')
conn.send(bytes('Received "Hello World"','UTF-8'))
conn.close()
global status1
status1.pack_forget()
status1.pack(side=RIGHT,padx=2,pady=2)
change = Button(frame, text="Change Host", width=10,command=change1).grid(row=0,column=2)
change2 = Button(frame, text="Change Port", width=10,command=change3).grid(row=1,column=2)
go = Button(frame, text="GO!",command=go1,width =10).grid(row=2,column=2)
frame.pack(side=LEFT)
mainloop()
Any help on the matter would be much appreciated! Thanks!
Your problems begin with this line:
host1 = Label(frame,text="Host: ").grid(row=0,column=0)
What you are doing is creating a label, using grid to place the label on the screen, then assigning host1 the result of the grid() command, which is the empty string. This makes it impossible to later refer to host1 to get a reference to the label.
Instead, you need to save a reference to the label. With that reference you can later change anything you want about the label:
host1 = Label(frame, text="Host: ")
host1.grid(row=0, column=0)
...
if (something_has_changed):
host1.configure(text="Hello, world!")
Take it from someone with over a decade of experience with tk, it's better to separate your widget creation and layout. Your layout will almost certainly change over the course of development and it's much easier to do that when all your layout code is in one place. My layouts may change a lot but my working set of widgets rarely does, so I end up only having to change one block of code rather than dozens of individual lines interleaved with other code.
For example, my code generally looks roughly like this:
labell = tk.Label(...)
label2 = tk.Label(...)
entry1 = tk.Entry(...)
label1.grid(...)
label2.grid(...)
entry1.grid(...)
Of course, I use much better variable names.
First, before going in depth with this problem. I want to highlight out a few things. In this line.
host2 = Label(frame,text=HOST,width=10).grid(row=0,column=1)
I want you to separate the gridding part from the declaration of the variable. Because it will create a No Type object that you cant work with. It will create many problems in the future that may take a lot of your time. If you have any variables structured like this that are not just going to be served as lines of text. Change the structure of that of that variable to the structure that I described above. Anyways, going back to what you where saying but in more depth is that to change the text of the Labels. What I would do if its going to be changed by function is in that function that you are wanting to change the text of the Label. Put in lines like this.
host2['text'] = 'Your New Text'
port2['text'] = 'Your New Text'
# or
host2.configure(text = 'Your New Text')
port2.configure(text = 'Your New Text')
This will change the text of your labels to the newly changed text or In other words replaces the text with the new text.

How can I model a scalable set of definition/term pairs?

Right now my flashcard game is using a prepvocab() method where I
define the terms and translations for a week's worth of terms as a dictionary
add a description of that week's terms
lump them into a list of dictionaries, where a user selects their "weeks" to study
Every time I add a new week's worth of terms and translations, I'm stuck adding another element to the list of available dictionaries. I can definitely see this as not being a Good Thing.
class Vocab(object):
def __init__(self):
vocab = {}
self.new_vocab = vocab
self.prepvocab()
def prepvocab(self):
week01 = {"term":"translation"} #and many more...
week01d = "Simple Latvian words"
week02 = {"term":"translation"}
week02d = "Simple Latvian colors"
week03 = {"I need to add this":"to self.selvocab below"}
week03d = "Body parts"
self.selvocab = [week01, week02] #, week03, weekn]
self.descs = [week01d, week02d] #, week03, weekn]
Vocab.selvocab(self)
def selvocab(self):
"""I like this because as long as I maintain self.selvocab,
the for loop cycles through the options just fine"""
for x in range(self.selvocab):
YN = input("Would you like to add week " \
+ repr(x + 1) + " vocab? (y or n) \n" \
"Description: " + self.descs[x] + " ").lower()
if YN in "yes":
self.new_vocab.update(self.selvocab[x])
self.makevocab()
I can definitely see that this is going to be a pain with 20+ yes no questions. I'm reading up on curses at the moment, and was thinking of printing all the descriptions at once, and letting the user pick all that they'd like to study for the round.
How do I keep this part of my code better maintained? Anybody got a radical overhaul that isn't so....procedural?
You should store your term:translation pairs and descriptions in a text file in some manner. Your program should then parse the text file and discover all available lessons. This will allow you to extend the set of lessons available without having to edit any code.
As for your selection of lessons, write a print_lesson_choices function that displays the available lessons and descriptions to the user, and then ask for their input in selecting them. Instead of asking a question of them for every lesson, why not make your prompt something like:
self.selected_weeks = []
def selvocab(self):
self.print_lesson_choices()
selection = input("Select a lesson number or leave blank if done selecting: ")
if selection == "": #Done selecting
self.makevocab()
elif selection in self.available_lessons:
if selection not in self.selected_weeks:
self.selected_weeks.append(selection)
print "Added lesson %s"%selection
self.selvocab() #Display the list of options so the user can select again
else:
print "Bad selection, try again."
self.selvocab()
Pickling objects into a database means it'll take some effort to create an interface to modify the weekly lessons from the front end, but is well worth the time.

Resources