Seite 1 von 2

ctypes ChooseFontW

Verfasst: Mittwoch 26. Oktober 2022, 15:39
von Fire Spike
Hallo Leute

Ich habe versucht ChooseColorW mit ctypes aufzurufen.
Schlussendlich sollte ich dann die Werte abrufen können.
Das Ganze sollte auch funktionieren. Leider öffnet sich aber kein Fenster in dem man die Schrift auswählen könnte.
Da ich mit C nicht sehr vertraut bin, weiss ich nicht mehr weiter. Ich habe es mit Hilfe der Dokumentation versucht in Python zu implementieren.
ChooseFontW callback function
CHOOSEFONTW structure
LOGFONTA structure
Beispiel in C

Code: Alles auswählen

import ctypes
import ctypes.wintypes as wtypes

class LOGFONT(ctypes.Structure):
    _fields_ = [
        ("lfHeight", wtypes.LONG),
        ("lfWidth", wtypes.LONG),
        ("lfEscapement", wtypes.LONG),
        ("lfOrientation", wtypes.LONG),
        ("lfWeight", wtypes.LONG),
        ("lfItalic", wtypes.BYTE),
        ("lfUnderline", wtypes.BYTE),
        ("lfStrikeOut", wtypes.BYTE),
        ("lfCharSet", wtypes.BYTE),
        ("lfOutPrecision", wtypes.BYTE),
        ("lfClipPrecision", wtypes.BYTE),
        ("lfQuality", wtypes.BYTE),
        ("lfPitchAndFamily", wtypes.BYTE),
        ("lfFaceName", ctypes.c_wchar * 32)
    ]

class CHOOSEFONT(ctypes.Structure):
    _fields_ = [
        ("lStructSize", wtypes.DWORD),
        ("hwndOwner", wtypes.HWND),
        ("hDC", wtypes.DWORD), # ignored
        ("lpLogFont", LOGFONT),
        ("iPntSize", wtypes.INT),
        ("Flags", wtypes.DWORD),
        ("rgbColors", wtypes.DWORD),
        ("lCustData", wtypes.LPARAM),
        ("lpfnHook", wtypes.DWORD), # ignored
        ("lpTemplateName", wtypes.LPCSTR),
        ("hInstance", wtypes.HINSTANCE),
        ("lpszStyle", wtypes.LPSTR),
        ("nFontType", wtypes.WORD),
        ("___MISSING_ALIGNMENT__", wtypes.WORD),
        ("nSizeMin", wtypes.INT),
        ("nSizeMax", wtypes.INT)
    ]

class FontChooser():
    CF_SCREENFONTS = 0x1
    CF_EFFECTS = 0x100
    font_chooser = ctypes.windll.Comdlg32.ChooseFontW

    def ask_font(self):
        struct = CHOOSEFONT()

        # ctypes.memset(ctypes.byref(struct), 0, ctypes.sizeof(struct))
        struct.lStructSize = ctypes.sizeof(struct)
        struct.Flags = wtypes.DWORD(self.CF_SCREENFONTS | self.CF_EFFECTS)

        self.font_chooser(ctypes.byref(struct))
        print(struct.rgbColors)

r = FontChooser()
r.ask_font()
Könnt ihr mir bitte helfen?
LG Fire Spike

Re: ctypes ChooseFontW

Verfasst: Mittwoch 26. Oktober 2022, 16:26
von __blackjack__
`ChooseFontW` scheint ja schon mal falsch zu sein, das ist der Name eines ``struct`` nicht der Name der Funktion. Da kommt keine Ausnahme?

`FontChooser` ist keine sinnvolle Klasse. Es macht keinen Sinn Exemplare davon zu erstellen, weil die gar keinen Zustand haben. Das ist eine etwas zu umständlich geschriebene Funktion. Ist das ”original” hier ja auch — eine Funktion.

Re: ctypes ChooseFontW

Verfasst: Mittwoch 26. Oktober 2022, 16:34
von Fire Spike
Da mit der Klasse hast du Recht. Ich bekomme keine Ausnahme. Es läuft vollständig durch.

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 16:11
von Fire Spike
Also 'ChooseFontW' ist die Funktion wo man dann 'CHOOSEFONTW' übergibt. Der Fehler muss also sonst wo liegen.
Noch andere Ideen?

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 16:33
von Sirius3
CHOOSEFONT erwartet als lpLogFont einen LP_LOGFONT und nicht LOGFONT.
Und Du mußt natürlich dieses Feld mit einem Pointer auf ein LOGFONT initialisieren, sonst weiß ChooseFont ja nicht, wo es die Font-Informationen hinschreiben soll.

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 16:37
von __blackjack__
@Fire Spike: Ich bleibe trotzdem dabei: Es ist die falsche Funktion. Die Dokumentation die Du verlinkst, hat gleich am Anfang eine Warnung, dass man die nicht direkt benutzen soll. Im C-Beispiel, welches Du ebenfalls verlinkst, wird die Funktion ja auch nicht verwendet.

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 16:53
von Fire Spike
@Sirius3 Danke für den Hinweis. Mit einem Pointer funktioniert es.
@__blackjack__ ChooseFontW funktioniert

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 17:20
von __blackjack__
@Fire Spike: Es ist egal ob das funktioniert oder nicht, laut Dokumentation sollte man es nicht benutzen. Warum machst Du das also?

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 19:55
von Fire Spike
Ich sehe keine Grund etwas anderes zu benutzen, wenn das funktioniert und in der Dokumentation kein guter Grund aufgezeigt wird. Wenn du das anderst siehst, kannst du mir gerne erklären, was nicht gut an dieser Überlegungen ist.

Re: ctypes ChooseFontW

Verfasst: Donnerstag 27. Oktober 2022, 20:49
von sparrow
Irgendjemand muss den Code ja geschrieben haben. Und der ist demjenigen, der die Dokumentation geschriebe hat, wahrscheinlich sehr nahe. Ich setze jetzt mal voraus, dass diese Menschen in diesem Umfeld wissen, was sie tun.
Die schreiben in die Dokumentation eine Warnung(!), dass die Funktion nicht direkt aufgerufen werden soll. Und sie geben ein Beispiel mit, wie man es machen soll.
Du ignorierst die Warnung und das Beispiel konsequent. Das hat sicher damit zu tun, dass du die Schnittstelle besser kennst als die Leute, die sie eigentlich geschrieben haben.

Re: ctypes ChooseFontW

Verfasst: Freitag 28. Oktober 2022, 07:05
von Sirius3
@__blackjack__, @sparrow: ChooseFont ist nur ein C-Macro, das entscheidet, ob ChooseFontW oder ChooseFontA aufgerufen werden soll, je nachdem, ob das C-Programm mit WideChars umgehen kann oder nicht.
Als Pythonnutzer muß man das händisch selbst entscheiden.
@Fire Spike: Warnungen sollte man nicht ignorieren, wenn man den Sinn dahinter verstanden hat, und weiß, dass man bei nicht-C-Programmen selbst die Verantwortung übernehmen muß, ist das aber Ok.

Re: ctypes ChooseFontW

Verfasst: Freitag 28. Oktober 2022, 15:34
von Fire Spike
Danke für eure Antworten. In Zukunft sollte ich wohl auf solche Warnungen achten.
Das mit ChooseFont war mir noch nicht klar.

Ich habe noch eine (hoffentlich) letzte Frage.
Ich versuche jetzt den Wert von lpLogFont abzurufen, was aber mit dieser Ausnahme endet:

Code: Alles auswählen

    print(struct.lpLogFont.contents)
ValueError: NULL pointer access
Einen Pointer habe ich ja abgerufen. Wieso stimmt der nicht?

Code: Alles auswählen

import ctypes
import ctypes.wintypes as wtypes

class LOGFONT(ctypes.Structure):
    _fields_ = [
        ("lfHeight", wtypes.LONG),
        ("lfWidth", wtypes.LONG),
        ("lfEscapement", wtypes.LONG),
        ("lfOrientation", wtypes.LONG),
        ("lfWeight", wtypes.LONG),
        ("lfItalic", wtypes.BYTE),
        ("lfUnderline", wtypes.BYTE),
        ("lfStrikeOut", wtypes.BYTE),
        ("lfCharSet", wtypes.BYTE),
        ("lfOutPrecision", wtypes.BYTE),
        ("lfClipPrecision", wtypes.BYTE),
        ("lfQuality", wtypes.BYTE),
        ("lfPitchAndFamily", wtypes.BYTE),
        ("lfFaceName", ctypes.c_wchar * 32)
    ]

class CHOOSEFONT(ctypes.Structure):
    _fields_ = [
        ("lStructSize", wtypes.DWORD),
        ("hwndOwner", wtypes.HWND),
        ("hDC", wtypes.DWORD), # ignored
        ("lpLogFont", ctypes.POINTER(LOGFONT)),
        ("iPntSize", wtypes.INT),
        ("Flags", wtypes.DWORD),
        ("rgbColors", wtypes.DWORD),
        ("lCustData", wtypes.LPARAM),
        ("lpfnHook", wtypes.DWORD), # ignored
        ("lpTemplateName", wtypes.LPCSTR),
        ("hInstance", wtypes.HINSTANCE),
        ("lpszStyle", wtypes.LPSTR),
        ("nFontType", wtypes.WORD),
        ("___MISSING_ALIGNMENT__", wtypes.WORD),
        ("nSizeMin", wtypes.INT),
        ("nSizeMax", wtypes.INT)
    ]


def ask_font():
    CF_SCREENFONTS = 0x1
    CF_EFFECTS = 0x100
    struct = CHOOSEFONT()

    struct.lStructSize = ctypes.sizeof(struct)
    struct.Flags = wtypes.DWORD(CF_SCREENFONTS | CF_EFFECTS)

    ctypes.memset(ctypes.byref(struct), 0, ctypes.sizeof(struct))
    
    ctypes.windll.Comdlg32.ChooseFontW(ctypes.byref(struct))
    print(struct.lpLogFont.contents)
    print(struct.rgbColors)

ask_font()

Re: ctypes ChooseFontW

Verfasst: Sonntag 30. Oktober 2022, 21:00
von Fire Spike
Ich nehme mal an, dass ihr mir nicht helfen konntet, weil der Code nicht funktioniert hat...
Hier nochmals der Funktionierende:

Code: Alles auswählen

import ctypes
import ctypes.wintypes as wtypes

class LOGFONT(ctypes.Structure):
    _fields_ = [
        ("lfHeight", ctypes.POINTER(wtypes.LONG)),
        ("lfWidth", wtypes.LONG),
        ("lfEscapement", wtypes.LONG),
        ("lfOrientation", wtypes.LONG),
        ("lfWeight", wtypes.LONG),
        ("lfItalic", wtypes.BYTE),
        ("lfUnderline", wtypes.BYTE),
        ("lfStrikeOut", wtypes.BYTE),
        ("lfCharSet", wtypes.BYTE),
        ("lfOutPrecision", wtypes.BYTE),
        ("lfClipPrecision", wtypes.BYTE),
        ("lfQuality", wtypes.BYTE),
        ("lfPitchAndFamily", wtypes.BYTE),
        ("lfFaceName", ctypes.c_wchar * 32)
    ]

class CHOOSEFONT(ctypes.Structure):
    _fields_ = [
        ("lStructSize", wtypes.DWORD),
        ("hwndOwner", wtypes.HWND),
        ("hDC", wtypes.DWORD), # ignored
        ("lpLogFont", ctypes.POINTER(LOGFONT)),
        ("iPntSize", wtypes.INT),
        ("Flags", wtypes.DWORD),
        ("rgbColors", wtypes.DWORD),
        ("lCustData", wtypes.LPARAM),
        ("lpfnHook", wtypes.DWORD), # ignored
        ("lpTemplateName", wtypes.LPCSTR),
        ("hInstance", wtypes.HINSTANCE),
        ("lpszStyle", wtypes.LPSTR),
        ("nFontType", wtypes.WORD),
        ("___MISSING_ALIGNMENT__", wtypes.WORD),
        ("nSizeMin", wtypes.INT),
        ("nSizeMax", wtypes.INT)
    ]


def ask_font():
    CF_SCREENFONTS = 0x1
    CF_EFFECTS = 0x100
    struct = CHOOSEFONT()

    struct.lStructSize = ctypes.sizeof(struct)
    struct.Flags = wtypes.DWORD(CF_SCREENFONTS | CF_EFFECTS)
    
    ctypes.windll.Comdlg32.ChooseFontW(ctypes.byref(struct))
    print(struct.lpLogFont.lfHeight)
    print(struct.rgbColors)

ask_font()

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 17:06
von Fire Spike
Kann mir bitte jemand helfen?
Ich habe wirklich schon alles versucht.

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 17:11
von __deets__
Dein vorletzter Post klang nach "alles geht, so ist es richtig". Daran mag's gelegen haben. Persoenlich bin ich zu selten unter Windows unterwegs. Allgemein wuerde ich ja zu einer Windows-spezifischeren Sprache wie C# raten, dann hast du so einen Aerger nicht (oder deutlich weniger).

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 17:27
von Fire Spike
In dem Fall mein Fehler.
Im Moment bekomme ich diesen Fehler mit obigem Code:

Code: Alles auswählen

    print(struct.lpLogFont.lfHeight)
AttributeError: 'LP_LOGFONT' object has no attribute 'lfHeight'
Ich habe schon mit Pointern herumgespielt, aber das half nicht.
Wenn es denn wirklich sein muss währe auch C# eine Option, aber ich möchte es eigentlich vermeiden.

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 17:33
von sparrow
Ich habe eine grundsätzlich Frage: Hat es einen besonderen Grund, warum du diesen steinigen Weg gehst?
Qt bietet zum Beispiel einen wunderbaren QFontDialog um Schriften zu wählen. Oder ist das hier etwas anderes?

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 17:54
von Fire Spike
Zum einen verwende ich kein Qt und zum anderen möchte ich das eigentlich so lösen.
Ich hatte nicht gedacht, dass es so schwierig sein könnte.

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 18:20
von sparrow
Welches GUI-Framework verwendest du denn?
Ich persönlich würde nur im äußersten Notfall irgend etwas mit ctypes machen. Gerade bei den Schnittstellen des Betriebssystems verliert man dadurch sämtliche Vorteile der Systemunabhängigkeit. Es sei denn, man schreibt nur für die eigene Schreibtischschublade.
In der Regel haben GUI-Frameworks etwas um eine Schrift auszuwählen. Oder man wirft einen Blick in Richtung der Paket auf PyPI.

Aber wenn du es als Challenge ansiehst, das so zu lösen: Do it.

Re: ctypes ChooseFontW

Verfasst: Montag 31. Oktober 2022, 19:01
von __deets__
Das ist ja nicht das erste mal, dass du mit der Wahl deiner tkinter-Waffe ohne Hose vor dem Gegner stehst. Ich erinner mich noch an die zinc-Geschichte. Qt ist besser, hier als auch damals. Warum nutzt du das nicht? Warum muss es mit dem Kopf durch die Wand sein?