Hilfe, ich will ein Fenster zentrieren!

Willkommen in der Transport Fever Community

Welcome to the fan community of Transport Fever and Train Fever, the economic simulators of Urban Games. The community is free for you to share and inform yourself about the game. We cultivate a friendly and objective interaction with each other and our team will be happy to answer any questions you may have.

 

Registration and use is of course free for you.

 

We wish you a lot of fun and hope for active participation.

The Team of the Transport-Fever Community

  • Wieder eines dieser schrecklichen Probleme, an die man sich zeitraubend Schrittchen für Schrittchen herantasten muss :(:huh::rolleyes::cursing:<X|| Warum nur?!


    Ich möchte doch NUR ein kleines Alert-Fenster aufpoppen lassen, und zwar exakt (!!!) in der Mitte des Bildschirms.


    Theoretisch habe ich die Lösung gefunden:

    Aber nur theoretisch ...


    Das Fenster klappt auch. Aber nur in der Auflösung 1920 x 1080 liegt es in der Mitte. Wähle ich z.B. meine Standardgröße 2560 x 1440, liegt es zu weit rechts. Wenn man die Gegenprobe macht und das Fenster einmal am rechten Rand ausrichtet (also screenSize.w - 500), liegt es nicht am rechten Rand, sondern überschreitet ihn. Daraus ist zu folgern, dass die GUI-Grundfläche kleiner sein muss als die Bildschirmauflösung, aber gleichzeitig über sie hinausläuft. Aber eben nicht in allen Auflösungen. Was ist da los - und wie bekomme ich den richtigen Wert? Oder ist das einfach nur ein böser Bug? Wobei es in den hauseigenen UG-Routinen ja zu funktionieren scheint, denn die Ingame-Fenster (z.B. die Warnmeldung oben im Spielfenster) werden exakt zentriert.


    Und nein, es hat nichts mit Vulcan und OpenGL zu tun, hab ich auch schon getestet.

  • Fenstergröße ermitteln und dann eben ausrechnen:


    local mainView = api.gui.util.getById("mainView")

    mainView:getContentRect()


    w und h


    -edit-

    Laut meinem Notizen, ziemlich am Anfang waren die Größen aber 100% und nicht UI skaliert, ich habe es nicht mehr in letzter Zeit getestet. Sprich in TPF2 kann es sein das die Werte bei 200% UI Skalierung falsch sind...

  • Ääääh ... hab ich doch gemacht, hab nur statt mainView screen als Variable benutzt. Dürfte eigentlich nichts ausmachen. Hmm, dann weiß ich auch nicht mehr weiter., vielleicht haben die da ja tatsächlich was geändert. :/ Oder mein Monitor tickt falsch. :) Du (oder war es jemand anders?) hattest auch mal was mit Faktor 0.9 drin. Ich hatte schon den Verdacht, das wär's, aber das würde dann ja wieder mit den Fällen kollidieren, wo es exakt stimmt.


  • Funkt bei mir, hat die Screensize des Ausgabefensters von TPF2, wenn ich im Fenster Modus Spiele ist es entsprechend der Fenstergröße. Aber das nutzt eben nicht den UI Skalierungsfaktor. (Ich hab mal die Frage via Buschfunk weitergeben)

  • Ja, danke, :) das ist doch schon mal was. :thumbup: Da muss einer aber wirklich erst drauf kommen! Wozu soll das gut sein? Wenn man auf mehreren Monitoren spielt? Ahja, jetzt ist's klar - wegen der Schriftgröße. Die sich allerdings weniger ändert als die Größe der Fenster, wenn man diese mit calcMinimumSize() automatisch an den Text anzupassen versucht. Auch so eine Merkwürdigkeit.


    Daraus ergibt sich allerdings eine weitere Frage: Kann man den Skalierungswert irgendwo abgreifen?

  • Ich glaube inzwischen eine Lösung gefunden zu haben. Sieht zumindest so aus, dass es auch ohne Kenntnis des Skalierungsfaktors funktioniert:

    An dieser Stelle gleich die Warnung, dass das alles noch experimentell und ohne Gewähr ist - für alle, die den Code übernehmen möchten.


    Erstaunlich, welcher Aufwand getrieben werden muss, um ein simples Fenster zu öffnen. Erstaunlich auch, dass man wohl erst die tatsächlichen Maße des Fensters zurückgegeben bekommt, nachdem das Fenster bereits geöffnet wird. Aber immerhin hätten wir ein Workaround - womöglich schon den Königsweg. Vielleicht doch mal UG fragen ... ;)


    Eine weitere Überlegung wäre noch, das Fenster schon in guiInit anzulegen und später an entsprechender Stelle aufzupoppen. Dort wird es witzigerweise unabhängig von den in setPosition angegebenen Werten in den unsichtbaren negativen Koordinatenbereich geschoben, allerdings so, dass ein Teil noch in den sichtbaren GUI-Bereich hineinragt. ^^


    Ob setVisible überhaupt notwendig ist, ist mir nicht ganz klar. Für genau einen Frame müsste das Fenster an der falschen Stelle sichtbar sein. Alternativ könnte man es auch außerhalb des Bildschirms platzieren, in der Hoffnung, dass es dort nie jemand zu sehen bekommt. Und da scheint mir setVisible die sicherere Lösung zu sein.


    Ganz sicher bin ich mir noch nicht, ob bei der obigen Anordnung irgendwelche Aktionen beim Framewechsel "verschluckt" werden könnten. :/

  • Ein interessanter Effekt dabei ist, dass state.openWindow schon wieder gelöscht ist, bevor das Fenster aufgebaut ist, allerdings gleichzeitig noch als Zombie-Variable irgendwo zwischen load und save herumschwirrt. Multithreading ist echt schwer zu verstehen. :D Auf jeden Fall sollte man mit state.openWindow keine Strings aus anderen Threads an das Fenster übergeben. ?(

  • Das verwirrende ist, dass jedes Gamescript 2x existiert, einmal im Script und einmal im Gui Thread.

    Obwohl die Funktionen eigentlich getrennt sind (außer load :D).

    Darüber habe ich mich hier mal ausgekotzt: Game Script => Save function, Unerklärliches verhalten

    Eigentlich macht es keinen Sinn, das in einer gemeinsamen Datei zu haben.


    Eine Zuweisung von state im Gui Thread

    state.openWindow =

    macht eig keinen Sinn, da ja state bei load wieder neugeladen wird.

  • Technisch gesehen, jein. :S


    Ein GameScript liegt im GameScript Repository in GameRes(sourcen). Eine Funktion wird in der Regel mit GameState ("das Spiel im Sinne der Spieldaten") aufgerufen.


    Das sind eine Menge C++ Funktion Closures (std::function bzw. boost), die dann gebunden an LUA Script States sind (GUI/Game) werden.


    (guiInit wird ziemlich früh geladen, daher kann man die UI auch erst wirklich beim ersten guiUpdate aufbauen)


    TPF2 benutzt mindestens zwei GameStates und load/save wird auch genutzt beim Übergang dieser beiden. Seit Dienstag kann meine CommonAPI2 Windows Dev Version so ein GameScript updateEvent via C++ Code auslösen wenn TPF2 die nächste Station eines Fahrzeugs auswählt.


    Man sollte den Skalierungsfaktor auch von einem Element ausrechnen können, das garantiert schon im UI vorhanden ist. (Zum Beispiel die Menüleiste unten). Habe aber gerade keine Zeit das mal zu testen...


    PS: Man kann den Skalierungfaktor während des Spiel ändern, das am Anfang des Spiel einmalig zu machen ist auch nicht wirklich richtig.

  • Im Gui Thread (guiInit, guiUpdate) macht es nur Sinn den state zu lesen.

    Wenn du von dort aus den state ändern willst, musst du ein ScriptEvent schicken und die Änderung im Script Thread machen.


    Aber prüfen ob das Fenster schon geöffnet wurde, kann man auch mit ner lokalen Variable machen

  • Quote

    Wenn du von dort aus den state ändern willst, musst du ein ScriptEvent schicken und die Änderung im Script Thread machen.

    Bingo! :thumbup: Ist zwar etwas kompliziert, aber andererseits auch einleuchtend.


    Quote

    Aber prüfen ob das Fenster schon geöffnet wurde, kann man auch mit ner lokalen Variable machen

    Im Grunde finden ja mehrere Dinge statt. Zunächst schicke ich einen Befehl von der Engine an GUI, um das Fenster zu öffnen. Da dieser Befehl mehrmals reinkommt (mal testen, wie es mit obiger Lösung funktioniert), muss ich prüfen, ob das Fenster schon offen ist. Das mache ich über die Id (Grüße an Enzojz :whistling:). Ich hatte da auch schon mit einer Variable außerhalb state gearbeitet, wollte aber dann doch irgendwelche mutmaßlichen Hacks vermeiden. Der dritte Vorgang ist die Übergabe von Strings an das Alert-Fenster, die in meinem hier veröffentlichen Code noch nicht implementiert ist. Ich hatte hierfür einen String in windowOpen reingepackt, aber - wie gesagt - er wurde schon wieder gelöscht, bevor er überhaupt an das Fenster übergeben wurde. Deshalb übergebe ich jetzt einen separaten String, natürlich auch in state, der hinterher nicht gelöscht wird und vermutlich bis in alle Ewigkeit im gameScript wie ein Pingpong-Ball hin- und herspringt. Aber vielleicht krieg ich das ja jetzt mit der von dir vorgeschlagenen Methode optimiert und kann womöglich noch eine der drei Variablen sparen.