Bildschirmgröße in mm (EDID) / Multi-Monitor

Plattformunabhängige GUIs mit wxWidgets.
Antworten
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Hallo,

ich habe folgendes Problem: Ich möchte gern ein Fenster in einer bestimmten absoluten Größe (nicht Pixel) auf einem beliebigen Bildschirm. Dazu brauche ich erstmal die nutzbare Fläche des jeweiligen Bildschirms (lässt sich per EDID auslesen). Zuerst dachte ich an wx.ScreenDC und die Methode GetSizeMM, leider funktioniert das aber nur für den Haupt-Monitor (liefert aber hier korrekte Werte soweit ich das sehen kann). Unter Windows hilft ctypes:

Code: Alles auswählen

import ctypes

HORZSIZE = 4
VERTSIZE = 6

screen_no = 0 # wird im "richtigen" Skript natürlich dynamisch gesetzt anhand der Auswahl einer ComboBox
dc = ctypes.windll.user32.GetDC(screen_no)
screen_size_mm = ctypes.windll.gdi32.GetDeviceCaps(dc, HORZSIZE), ctypes.windll.gdi32.GetDeviceCaps(dc, VERTSIZE)
Aber ich brauche diese Funktionalität halt auch unter Linux und Mac OS X...
Über Hinweise wäre ich sehr dankbar :)

*edit* Ich stelle gerade fest, dass der Code oben so auch nicht funktioniert wie ichs mir dachte :(
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

So etwa?

Code: Alles auswählen

import wx
app = wx.App()
scr = wx.ScreenDC()
size = scr.GetSizeMM()
MfG
HWK
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Nun ja, so weit war ich ja auch schon :wink:. Aber so bekomme ich nur die Größe des Hauptbildschirms, oder? Für Zweit- oder Drittschirme scheints keine Möglichkeit zu geben :cry:

Wäre schön, wenn man dem Aufruf von wx.ScreenDC einfach die Nummer des gewünschten Bildschirms als Parameter mitgeben könnte. Eventuell werd ich das mal als Feature-Request in der wxPython Mailingliste posten.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Sorry! Habe Deinen Post nicht genau genug gelesen. :oops:
MfG
HWK
lunar

Unter Linux könntest du die Ausgabe von "xdpyinfo" parsen.

Btw, ist dir eigentlich klar, dass das zumindest unter X11 prinzipiell gar nicht funktionieren kann?
shakebox
User
Beiträge: 175
Registriert: Montag 31. März 2008, 17:01

ich bezweifle auch dass das sauber funktioniert, egal auf welchem System. Ich glaub ich wuerde das ja ueber eine userbasierte Kalibrierung machen:

Einfach ein Fenster auf dem jeweiligen Monitor ausgeben und bestimmte Strecken darstellen. Die soll der User vermessen und die Groesse eintippen. Das nimmst Du dann als Umrechnungsfaktor.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Vielleicht helfen wx.Display(), wx.DisplaySize() und wx.DisplaySizeMM()?
MfG
HWK
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

@HWK: Macht nichts, kann ja passieren :) *edit* Nachtrag: wx.ScreenDC().GetSizeMM() und wx.DisplaySizeMM() machen zwar genau das, was ich brauche, nur halt leider nur für den ersten Monitor.

@lunar: Ok, ich muss mich wohl damit abfinden, dass es keinen einfachen Weg nur mit Python und wxPython gibt. Ich habe hier zwar (funktionierenden) C-Code, der ist aber nicht von mir und ich habe leider wenig Ahnung von C, oder wie ich entsprechende Funktionalität in Python nachbilden könnte (oder obs überhaupt geht).
Ich werds wahrscheinlich so machen, ComboBox in der man die Display-Diagonale in Inch eingeben/auswählen kann, die mm-Abmessungen lassen sich dann daraus und der Pixel-Auflösung errechnen.
Zuletzt geändert von fhoech am Freitag 29. August 2008, 22:39, insgesamt 1-mal geändert.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Warum bindest Du dann nicht den C-Code ein? Stichwort: Extending Python.
MfG
HWK
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Guter Hinweis, danke, bin ich noch nicht drauf gekommen. Habe auch nicht allzuviel Ahnung von C, aber falls ich was Brauchbares hinbekomme melde ich mich nochmal :)
lunar

Was willst du eigentlich machen? Warum brauchst du den die physikalischen Abmessungen deines Fensters?
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

@lunar: Hier etwas mehr Background. Ich schreibe ein GUI für einige Komponenten von Argyll CMS, einem Open-Source-Farbmanagement-System auf Kommandozeilenbasis, genauer gesagt für dispcal, dispread und colprof. Mit diesen dreien lässt sich ein Monitor kalibrieren. Dazu wird ein Messfeld angezeigt (von dispcal / dispread), von dem Farbwerte mittels eines Messgeräts ausgelesen werden. Argyll benutzt als Größenangabe dieses Messfelds keine relativen Pixelgrößen, sondern geht immer von einem Rechteck mit 100x100 mm aus. Dieses lässt sich per Kommandozeilenoptionen skalieren und verschieben (proportional).
Beispiel: Damit das Messfeld sowohl auf einem 40" HD-Ready TV (Auflösung 1360x768) wie auch einem 20" TFT (Auflösung 1600x1200) gleich gross ist (also standardmässig 100x100 mm), benutzt Argyll zur Umrechnung der absoluten mm-Maße in Pixel die EDID-Angaben des jeweiligen Monitors. Diese erhält es durch Aufruf diverser betriebssystemspezifischer Funktionen. Das funktioniert gut (gemessene Abweichung der Größe des Messfelds zwischen den zwei Schirmen im Beispiel 1-2 mm).
Ich möchte in meinem GUI dem Benutzer die Möglichkeit geben, die Größe und Position mittels eines frei verschieb-und skalierbaren Fensters festzulegen. Um jedoch aus den relativen Maßen dieses Fensters die richtigen Kommandozeilenoptionen zur Skalierung errechnen zu können, brauche ich wieder die korrekten mm-Maße des Monitors, auf dem das Messfenster dargestellt wird. Unter Windows und Linux bekomme ich zumindest die des Haupt-Monitors mit wx.DisplaySizeMM (unter Mac OS stimmen die von DisplaySizeMM gelieferten Werte aber nicht mit denen unter Windows oder Linux überein. DisplaySizeMM verlässt sich unter MacOS scheinbar auf die Angaben von NSScreen und nicht auf diejenigen von Quartz Display Services. Ist aber nur ne Vermutung von mir, habe jetzt nicht im wxPython Sourcecode nachgesehen).

(BTW, der C-Code den ich erwähnt habe, der unter Argyll für die Positionierung und Skalierung des Messfensters zuständig ist, findet sich im Argyll-Sourecode in dispwin.c, Zeile 2777+)

@HWK: Danke für die Links. Ich denke, die Herausforderung für mich wird sein, dass der C-Code zur Ermittlung der Größe eines Displays einen Display-Pointer erwartet, und nicht etwa einen numerischen Index, wie ihn etwa wx.Display.GetFromWindow liefert. Ich werd schauen müssen, wie Displays im C-Code enumeriert werden und dann zwischen beiden Methoden übersetzen.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Der Pointer wird scheinbar in get_a_display ab Zeile 962 aus dem Display-Index gebildet.
MfG
HWK
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Habs hinbekommen :) RealDisplaySizeMM.zip

Unter Linux und Windows kann man die distutils nutzen oder die fertigen Module im Unterverzeichnis dist, unter OS X musste ich auf Xcode ausweichen (beim build mit distutils fehlte immer das Symbol ___CFConstantStringClassReference, gibt zwar einen Workaround mit extra_link_args = ['-framework CoreFoundation'], dieser funktionierte bei mir allerdings nicht, werd mir das bei Gelegenheit nochmal genauer anschaun).

python setup.py install

import RealDisplaySizeMM
n = <Nummer des Displays>
RealDisplaySizeMM.RealDisplaySizeMM(n)

Danke nochmal für die Tips :)
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Sehr schön. Bei mir unter Windows XP mit allerdings nur einem Monitor funktioniert es.
Und Du hast wirklich kaum Ahnung von C? :wink:
MfG
HWK
fhoech
User
Beiträge: 143
Registriert: Montag 9. April 2007, 18:26

Und Du hast wirklich kaum Ahnung von C?
Ja, wirklich ^^ Das Ergebnis ist ja jetzt eigentlich ein mehr oder minder copy&paste aus dem Argyll Code. Ich hab auch teilweise gekämpft bis es funktioniert hat (hatte zuerst Probleme mit dem build unter Windows, weil falsche Compiler-Version. Dann das Problem mit dem fehlenden Symbol bei Verwendung von distutils unter Mac OS, konnte ich zum Glück mit Xcode umgehen - aber schöner wärs schon, wenns auch da mit distutils funktionieren würde. Mal schaun, vielleicht krieg ich das auch noch hin ^^).
Antworten