I have recently needed to get the icon for any file type, and I want a big one, so I am using SHImageList, as this C# answer suggested.
I have had difficulty getting anything to work. I was using SHGetFileInfo, but that only returns 32x32px icons, and I would prefer the 256x256 ones.
Based on the reference I can figure out the first two arguments, but I have yet to figure out what the third argument is. Am I just supposed to put None? Though based on this blog post the third argument is an HImageList, but I have yet to find the structure of any HImageList.The relavent snippet of my code is:
SHIL_JUMBO = 0x000000004
iidImageList=GUID("{46EB5926-582E-4017-9FDF-E8998DAA0950}")
hico=??
hres=ctypes.windll.shell32.SHGetImageList(SHIL_JUMBO,byref(iidImageList),hico)
hdc.DrawIcon( (0,0), hico )
hbmp.SaveBitmapFile( hdc, tempDirectory + "\Icontemp.bmp")
How should I initialize hico and of what type??
Also, to avoid the XY problem, an answer to this question can give an alternative way of getting the icon of any file type. (Preferably using Pillow or PyQt)
EDIT: Well, I guess I wasn't clear about what I need. I need to initiate an HImageList type. I changed the title, to reflect the edits. Also, to the XY problem. A requirement is that the program is in Python (unless it can be shown that that is impossible).
SHGetImageList returns an image list, not an icon.
You need to use it in conjunction with SHGetFileInfo:
SHGetFileInfo gives you the icon index within the system image list (use the SHGFI_SYSICONINDEX flag)
SHGetImageList gives you the jumbo image list (use SHIL_JUMBO).
You can then draw the icon using ImageList_DrawEx, or extract it from the icon list as an HICON using the ImageList_ExtractIcon macro or by calling ImageList_GetIcon. Note that although SHGetImageList returns an IImageList interface, a pointer to these is freely convertible to HIMAGELIST.
Psuedo-code:
SHFILEINFO sfi;
SHGetFileInfo(L"c:\file.txt", 0, &sfi, sizeof(sfi),
SHGFI_SYSICONINDEX);
HIMAGELIST hil;
SHGetImageList(SHIL_JUMBO, IID_IImageList, &hil);
ImageList_DrawEx(hil, sfi.iIcon, hdc, x, y, 0, 0,
CLR_NONE, CLR_NONE, ILD_NORMAL);
Related
I am seeing that VS Code is getting intellisense hints from the comments I put in my class functions:
def GyroDriveOnHeading(self, desiredHeading, desiredDistance):
"""
Drives the robot very straight on a given heading for a \
given distance, using the acceleration and the gyro. \
Accelerates to prevent wheel slipping. \
Gyro keeps the robot pointing on the desired heading.
Minimum distance that this will work for is about 16cm.
If you need to go a very short distance, use move_tank.
Parameters
-------------
desiredHeading: On what heading should the robot drive (float)
type: float
values: any. Best if the desired heading is close to the current heading. Unpredictable robot movement may occur for large heading differences.
default: no default value
desiredDistance: How far the robot should go in cm (float)
type: float
values: any value above 16.0. You can enter smaller numbers, but the robot will still go 16cm
default: no default value
Example
-------------
import base_robot
br = base_robot.BaseRobot()
br.GyroDriveOnHeading(90, 40) #drive on heading 90 for 40 cm
"""
Which gives me a really nice popup when I use that function:
As you can see here, since I am about to enter the first parameter, desiredHeading, the intellisense was smart enough to know that the line in the comments under "Parameters" that starts with the variable name should be the first thing displayed in the hint. And indeed, once I type the first parameter and a comma, the first line of the intellisense popup changes to show the information about desiredDistance.
But I would like to know more about how the comments should be written. I read about the numpy style guide as being close to a standard most widely adopted, but when I change the parameter documentation format to match numpy (and somethihng called Sphinx has something to do with this too, I think), the popups were not the same. Really, I just want to see the documentation on how to document (yikes!) my python code so it renders correct intellisense. For example, how can I bold a word in the middle of a sentence? Are there other formatting options available?
This is just for a middle-school robotics club, nothing like production code for real programmers. Nothing is broken, I just want to learn more about how this works.
That's it for docstrings in python, about it's introduction:
https://docs.python.org/3.10/tutorial/controlflow.html#documentation-strings
https://peps.python.org/pep-0287/
In addition, you can use the type stub of the parameter in this way.
def open(url: str, new: int = ..., autoraise: bool = ...) -> bool: ...
I just set up my VS Code to use Black, the python formatter. The default format puts a dict key on a new line when referencing a value, like this,
my_function_call(
my_dict[
"my_key"
],
function_param2=var,
function_param3=another_var
)
I never write keys on a new line like that when referencing a dictionary. Instead, I would rather set it up on the same line, like so,
my_function_call(
function_param1=my_dict["my_key"],
function_param2=var,
function_param3=another_var
)
Is there a way to save specific modifications like this, or is black a take-what-you-get kind of extension? I haven't found anything in their docs or in a google search mentioning modifications
EDIT: Just checked and this is not due to black's default line length. The line of code I'm testing is not longer than default 88 chars.
No, you cannot configure how Black formats your code except for setting the line length. It intentionally doesn't have options to control formatting.
Black is the uncompromising Python code formatter. By using it, you agree to cede control over minutiae of hand-formatting. – PyPI
On Anki, the front of a card have "X+Y?" and the back shows "Z". For example, front "4+7?" and back "11" But I want next time that I see this card the numbers be different, randomizing the X, Y and Z elements. This could be possible picking the values from a pool previously defined by me, I guess.
Searching it on here, I found this code:
import random
foo = ['a', 'b', 'c', 'd', 'e']
print(random.choice(foo))
How can I put it to work on Anki? Because I just tried to copy it and paste in card model editor, but nothing happened. Sorry, I'm not a programmer, so I'd be grateful to know anything that can help me functionalize this random display. Thanks for your time.
Even though it is possible (but convoluted to make it happen), it is usually (very heavily) discouraged to make use of random content on Anki. The reason is the following: if some content has a change of being displayed at the front of a card, then it means you want to memorize it. But then, it means that you are bloating several things that you want to learn into a single card. For several reasons (among which: Anki is optimized to work with the assumption that each card corresponds to a single, atomic thing you want to learn. Breaking that assumption can only make it work worse, which in the end makes you spend more time trying to learn that stuff), it's better to just have a card for each possible thing you want to learn.
Edit having read my words of warning, I'll leave you judge of whether it's really a good decision to do what you want.
The first thing to understand is that even though Anki is mainly written in Rust and Python (which are two programming languages), and even though it supports add-ons written in Python, it's not Python (nor Rust) that should be used for this purpose. I say this because the snippet of code you provided is written in Python.
The reason behind this is that Anki uses webviews to render cards, which means that when you see a card, it's just like if you were seeing a website. Therefore, if you only want execute code when you are reviewing the cards (and not, say, automatically generate cards), the language you have to use is JavaScript. Unfortunately, I am not a JavaScript programmer, so my answer may suck. Fortunately, JavaScript is a rather simple programming language, very well documented, and your request is simple enough for me not to have much room to screw the code (meaning this answer should not suck too much). This being said, let's make it work:
Add a field to your notes that will hold the possible values that will be shown. To make it simple, let's assume none of these values will contain commas, so that we can simply write the values comma-separated. Let's say you called this field Values (rename it as you like). By default, it's going to pick the first of these values if it cannot pick at random. More on this at the end.
Now open the template edit window for this note. If you are in the browser, it should be the Cards... button.
Select Front Template (it should be selected by default). At the top of the template, add the following, which is code that will allow the randomly chosen value to be kept also when you reveal the answer (because by default it would just re-evaluate the whole script, picking at random again).
<script>
// v1.0.0 - https://github.com/SimonLammer/anki-persistence/blob/cd2ca88e019dc3b8f32dad623932c1eabdba7e21/script.js
if(void 0===window.Persistence){var _persistenceKey="github.com/SimonLammer/anki-persistence/",_defaultKey="_default";if(window.Persistence_sessionStorage=function(){var e=!1;try{"object"==typeof window.sessionStorage&&(e=!0,this.clear=function(){for(var e=0;e<sessionStorage.length;e++){var t=sessionStorage.key(e);0==t.indexOf(_persistenceKey)&&(sessionStorage.removeItem(t),e--)}},this.setItem=function(e,t){null==t&&(t=e,e=_defaultKey),sessionStorage.setItem(_persistenceKey+e,JSON.stringify(t))},this.getItem=function(e){return null==e&&(e=_defaultKey),JSON.parse(sessionStorage.getItem(_persistenceKey+e))},this.removeItem=function(e){null==e&&(e=_defaultKey),sessionStorage.removeItem(_persistenceKey+e)})}catch(e){}this.isAvailable=function(){return e}},window.Persistence_windowKey=function(e){var t=window[e],n=!1;"object"==typeof t&&(n=!0,this.clear=function(){t[_persistenceKey]={}},this.setItem=function(e,n){null==n&&(n=e,e=_defaultKey),t[_persistenceKey][e]=n},this.getItem=function(e){return null==e&&(e=_defaultKey),null==t[_persistenceKey][e]?null:t[_persistenceKey][e]},this.removeItem=function(e){null==e&&(e=_defaultKey),delete t[_persistenceKey][e]},null==t[_persistenceKey]&&this.clear()),this.isAvailable=function(){return n}},window.Persistence=new Persistence_sessionStorage,Persistence.isAvailable()||(window.Persistence=new Persistence_windowKey("py")),!Persistence.isAvailable()){var titleStartIndex=window.location.toString().indexOf("title"),titleContentIndex=window.location.toString().indexOf("main",titleStartIndex);titleStartIndex>0&&titleContentIndex>0&&titleContentIndex-titleStartIndex<10&&(window.Persistence=new Persistence_windowKey("qt"))}}
</script>
This code comes from anki persistance. Also, when editing templates, please do not write values above the snippet, always under (it won't change how it renders, but it will ensure all this code is loaded before you do anything else).
Select the Back Template, and add the following snippet at the top of the template (it's the same thing as before):
<script>
// v1.0.0 - https://github.com/SimonLammer/anki-persistence/blob/cd2ca88e019dc3b8f32dad623932c1eabdba7e21/script.js
if(void 0===window.Persistence){var _persistenceKey="github.com/SimonLammer/anki-persistence/",_defaultKey="_default";if(window.Persistence_sessionStorage=function(){var e=!1;try{"object"==typeof window.sessionStorage&&(e=!0,this.clear=function(){for(var e=0;e<sessionStorage.length;e++){var t=sessionStorage.key(e);0==t.indexOf(_persistenceKey)&&(sessionStorage.removeItem(t),e--)}},this.setItem=function(e,t){null==t&&(t=e,e=_defaultKey),sessionStorage.setItem(_persistenceKey+e,JSON.stringify(t))},this.getItem=function(e){return null==e&&(e=_defaultKey),JSON.parse(sessionStorage.getItem(_persistenceKey+e))},this.removeItem=function(e){null==e&&(e=_defaultKey),sessionStorage.removeItem(_persistenceKey+e)})}catch(e){}this.isAvailable=function(){return e}},window.Persistence_windowKey=function(e){var t=window[e],n=!1;"object"==typeof t&&(n=!0,this.clear=function(){t[_persistenceKey]={}},this.setItem=function(e,n){null==n&&(n=e,e=_defaultKey),t[_persistenceKey][e]=n},this.getItem=function(e){return null==e&&(e=_defaultKey),null==t[_persistenceKey][e]?null:t[_persistenceKey][e]},this.removeItem=function(e){null==e&&(e=_defaultKey),delete t[_persistenceKey][e]},null==t[_persistenceKey]&&this.clear()),this.isAvailable=function(){return n}},window.Persistence=new Persistence_sessionStorage,Persistence.isAvailable()||(window.Persistence=new Persistence_windowKey("py")),!Persistence.isAvailable()){var titleStartIndex=window.location.toString().indexOf("title"),titleContentIndex=window.location.toString().indexOf("main",titleStartIndex);titleStartIndex>0&&titleContentIndex>0&&titleContentIndex-titleStartIndex<10&&(window.Persistence=new Persistence_windowKey("qt"))}}
</script>
Go back to Front Template, and add the following where you want the value to be shown. If you don't know, just put it anywhere, check at the end where it renders well, and change it then, so you have visual feedback. Also avoid having other tags with id=values.
<div id="values">{{Values}}</div>
If you renamed the field Values, change the one between double braces too.
6. Add at the bottom of the template the following. This will be responsible for picking a value at random.
<script>
var valuesNode = document.getElementById("values");
var values = valuesNode.innerText.split(',');
var defaultValue = values[0];
var value = defaultValue;
if (Persistence.isAvailable()) {
value = Persistence.getItem();
if (value == null) {
value = values[Math.floor(Math.random() * values.length)];
Persistence.setItem(value);
}
}
valuesNode.innerText = value;
</script>
Go to the Back Template, and add the following where you want the value to be shown (just like in the front template):
<div id="values">{{Values}}</div>
At the bottom of the template, add the following. This will be responsible for showing the randomly picked value when showing the answer.
<script>
var valuesNode = document.getElementById("values");
var values = valuesNode.innerText.split(',');
var defaultValue = values[0];
var value = defaultValue;
if (Persistence.isAvailable()) {
value = Persistence.getItem();
Persistence.clear();
}
valuesNode.innerText = value;
</script>
Here I'm going to explain why there is a default value. This is due to the fact that several Anki clients handle JavaScript differently. anki persistance should work when you are reviewing, but it may not work when you are previewing a card. In these cases, it could still pick a random value, but when you would reveal the answer it could not "remember" which value it picked, so it would pick an other one at random. To prevent that, if it knows it will not remember, it will just pick the default one, so it's consistent when you reveal the answer.
I am building an automation script with python using pywinauto, and I am stumped on this part. So far I'm able to start the app, or connect to it. I've toggled through the windows in the interface, and now it needs to somehow read the value and compare to the contents of a .csv file and continue with more functions. The app has multiple windows and one of them uses a spreadsheet type interface. There is not a find/replace feature, or else I could just use that.
Now comes the challenge. It needs to "see" the string within a cell and I can easily do this using AccExplorer or Inspect.exe.
This is the cell structure in the app, with the selected item "CAM 2".
Cell example from the app
AccExplorer window showing results of the cell
And this is the result provided by AccExplorer. The red circle indicates the "value" I wish to find, and use for comparison. (I have found that searching for this topic on "value" results in answers that are too vague, rather than my literal need to find the value of "value" in this case.)
By using this code in my script passing in the class of the window provided by the AccExpolorer tool (red arrow for the class)
edit = wdow['WindowsForms10.Window.8.app.0.378734a']
props = edit.GetProperties()
print(props)
It does not return the "Value" field or its property in this case should be "Cam 2"
{'class_name': 'WindowsForms10.Window.8.app.0.378734a',
'friendly_class_name': 'WindowsForms10.Window.8.app.0.378734a',
'texts': [''], 'control_id': 1639674, 'rectangle': <RECT L0, T47, R1366, B746>,
'is_visible': True, 'is_enabled': True, 'control_count': 76, 'style': 1442906112,
'exstyle': 65536, 'user_data': 0, 'context_help_id': 0,
'fonts': [<LOGFONTW 'MS Shell Dlg' -11>],
'client_rects': [<RECT L0, T0, R1366, B699>],
'is_unicode': True, 'menu_items': []}
I am rather new to python (and programming in general) but I have been doing quite well at grasping all of this. I am aware of the backend, which I have not had luck with using UIA, and it seems to be working so far with the default. Also, I've tried using SWAPY and it displays a lot of class names as duplicates, and does not show this level of cell values directly.
The main question is what would I be doing wrong to get this data, or is it even possible to get it this way? I am open to any suggestions or even using other libraries. I just figured this would be the cleanest and easiest. Thanks!
For begin read getting started guide and see some examples
You choose not better way to get cell of DataGridView, try to use UIA backend for that
from pywinauto import Desktop
dlg = Desktop(backend="uia")["YourApplicationName"]
# use that function for found your DataGridView
#dlg.print_control_identifiers()
datagrid = dlg.DataGridView
# use for found some particular cell
#datagrid.print_control_identifiers()
# in my case it was DataItem
cell = dlg.DataGridView.DataItem
# way to get item value
print(cell.legacy_properties()['Value'])
You also can use indexes for choose from a lot of same cells, like "DataItem0" or get all cells using lambda:
cells = [child for child in datagrid.descendants() if child.element_info.control_type == "DataItem"]
for cell in cells:
print(cell.legacy_properties()['Value'])
I'm getting the error in the title when I try to use shapely.wkt.loads on the following input:
POLYGON((-93.577695846689437 40.813390731817726,-93.577674865779628 40.813444137603014,-93.577722549304582 40.8136196133706,-93.577945709640048 40.814004897950532,-93.5781135556297 40.814165115070466,-93.578243255589527 40.814229965262996,-93.578363418973865 40.814268111930119,-93.578405380213241 40.814252853305611,-93.578418731892242 40.814207077283442,-93.578376770009427 40.81411170971851,-93.578311920291867 40.814050674367543,-93.578300476322624 40.814008712491074,-93.578235626128318 40.813978195044577,-93.5779953002333 40.813646316512269,-93.577934265283389 40.813581466662242,-93.577924728143131 40.813535690301279,-93.577777862415886 40.813383102422016,-93.577695846689437 40.81339073181772))
Saving you the trouble of scrolling through all that, it's in WKT format. It's one of about 100 Polygons I'm reading in, and it's the only one throwing this error. To be clear, when I call:
p = loads('POLYGON((-93.577695846689437 40.813390731817726,-93.577674865779628 40.813444137603014,-93.577722549304582 40.8136196133706,-93.577945709640048 40.814004897950532,-93.5781135556297 40.814165115070466,-93.578243255589527 40.814229965262996,-93.578363418973865 40.814268111930119,-93.578405380213241 40.814252853305611,-93.578418731892242 40.814207077283442,-93.578376770009427 40.81411170971851,-93.578311920291867 40.814050674367543,-93.578300476322624 40.814008712491074,-93.578235626128318 40.813978195044577,-93.5779953002333 40.813646316512269,-93.577934265283389 40.813581466662242,-93.577924728143131 40.813535690301279,-93.577777862415886 40.813383102422016,-93.577695846689437 40.81339073181772))')
I get the error: shapely.geos.ReadingError: Could not create geometry because of errors while reading input.
I even went through the trouble of parsing it up into regular shapely.geometry.Polygon format. Then, it works fine. But I'd rather not clutter code with annoying string parsing (and an ugly try/except). And, of course, the shapely/wky.py file tells me absolutely nothing... If anyone knows what's going on/how to fix it, I'd appreciate it. Thanks!
The geometry contains non-closed rings. Looking at the first and last coordinate:
-93.577695846689437 40.813390731817726
-93.577695846689437 40.81339073181772
Adding 6 at the end of the last coordinate string will make the two equal, and the outer shell a closed linear ring required to make a polygon.