ctypes ChooseFontW

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`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.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Da mit der Klasse hast du Recht. Ich bekomme keine Ausnahme. Es läuft vollständig durch.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Also 'ChooseFontW' ist die Funktion wo man dann 'CHOOSEFONTW' übergibt. Der Fehler muss also sonst wo liegen.
Noch andere Ideen?
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

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.
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@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.
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

@Sirius3 Danke für den Hinweis. Mit einem Pointer funktioniert es.
@__blackjack__ ChooseFontW funktioniert
Benutzeravatar
__blackjack__
User
Beiträge: 14076
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Fire Spike: Es ist egal ob das funktioniert oder nicht, laut Dokumentation sollte man es nicht benutzen. Warum machst Du das also?
“Vir, intelligence has nothing to do with politics!” — Londo Mollari
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

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.
Sirius3
User
Beiträge: 18278
Registriert: Sonntag 21. Oktober 2012, 17:20

@__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.
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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()
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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()
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

Kann mir bitte jemand helfen?
Ich habe wirklich schon alles versucht.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

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).
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

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?
Fire Spike
User
Beiträge: 329
Registriert: Montag 13. Mai 2019, 16:05
Wohnort: Erde

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.
Benutzeravatar
sparrow
User
Beiträge: 4540
Registriert: Freitag 17. April 2009, 10:28

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.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

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?
Antworten