Fenster im sichtbaren Bereich?

Hallo in die Runde,
ich habe mir seinerzeit eine Routine gebastelt, die prüft, ob das Fenster im sichtbaren Bereich ist und ob man an die Fenstertitelzeile kommt. Offenbar funktioniert sie nicht, wenn zwei (oder mehr?) Monitore vorhanden sind. Insbesondere, wenn der Hauptmonitor rechts steht.

Hat hier jemand eine Routine, die solches erledigt oder gibt es dafür eine Funktion, die das übernimmt?

Gruß, Metti.

1 Like

Oh wei, ich habe da Stunden herumgebastelt. Mit 2 Monitoren funktioniert mein Code. Soweit ich mich erinnere, macht aber der dritte Probleme. Es gibt für macOS ein Declare.

if ParentWindow = nil then return
dim isNewPrefs as Boolean = not Globals.thePrefs.IsPrefAvailable(WindowTitle + "_Top")

'get pref values
dim PrefValueTop as Integer = Globals.thePrefs.GetPrefNumber(WindowTitle + "_Top")
dim PrefValueLeft as Integer = Globals.thePrefs.GetPrefNumber(WindowTitle + "_Left")
dim PrefValueWidth as Integer = Globals.thePrefs.GetPrefNumber(WindowTitle + "_Width")
dim PrefValueHeight as Integer = Globals.thePrefs.GetPrefNumber(WindowTitle + "_Height")
if PrefValueWidth = 0 then PrefValueWidth = ParentWindow.Bounds.Width
if PrefValueHeight = 0 then PrefValueHeight = ParentWindow.Bounds.Height
if ParentWindow.MinimumWidth > PrefValueWidth then PrefValueWidth = ParentWindow.MinimumWidth
if ParentWindow.MinimumHeight > PrefValueHeight then PrefValueHeight = ParentWindow.MinimumHeight

'set the rect
dim theRect as REALbasic.Rect
if isNewPrefs then
  theRect = new REALbasic.Rect(100, 100, ParentWindow.Width, ParentWindow.Height) 'dummy values
else
  theRect = new REALbasic.Rect(PrefValueLeft, PrefValueTop, PrefValueWidth, PrefValueHeight)
end if

'Find screen.
Dim screenID as integer
For l as integer = 0 to screenCount - 1
  if theRect.top >= screen(l).top and theRect.center.x > screen(l).left and theRect.center.x < (screen(l).left + screen(l).width) then screenID = l
next
lastScreen = screenID
Dim ShowOnScreen as screen = screen(screenID)

'for left and top we need to recalculate the values if the prefs are new, only for top if the prefs are not new
if isNewPrefs then
  if ParentWindow.Width < 900 then PrefValueTop = (Screen(ShowOnScreen).Height - ParentWindow.Bounds.Height)/2
  PrefValueLeft = (Screen(ShowOnScreen).Width - ParentWindow.Width)/2
  theRect = new REALbasic.Rect(PrefValueLeft, PrefValueTop, PrefValueWidth, PrefValueHeight)
end if

dim ScreenHeight as Integer = ShowOnScreen.AvailableHeight
dim theTop as Integer
if ShowOnScreen.AvailableTop < 0 then
  theTop = -min(-theRect.top, -ShowOnScreen.availabletop)
else
  theTop = max(theRect.top, ShowOnScreen.availabletop)
end if

if ShowOnScreen.AvailableTop > 0 then
  theRect.Top = Min(theTop - ShowOnScreen.AvailableTop, ScreenHeight) + ShowOnScreen.AvailableTop
else
  theRect.Top = min(theTop, ScreenHeight)
end if
theRect.Left = min(max(theRect.left, ShowOnScreen.availableLeft), ShowOnScreen.availableLeft + (ShowOnScreen.availableWidth))

if ParentWindow.ToolbarVisibleMBS and theRect.Height <= ParentWindow.MinimumHeight + 78 then
  theRect.Height = ParentWindow.MinimumHeight + 78
end if
theRect.Height = min(theRect.height, ShowOnScreen.AvailableHeight)
theRect.Width = min(theRect.Width, ShowOnScreen.AvailableWidth - 20)

ParentWindow.Bounds = theRect

Wie kommt denn das zu Stande?
Wird das Fenster zentriert geöffnet und ist höher wie der Bildschirm?
Oder schiebt es jemand raus?

Dieses Fenster .Bounds sind die Außen Maße welche man nur setzen kann wenn man ein neues Rect Objekt übergibt.

In den MBS Xojo Plugins gibt’s window.ConstrainWindowToScreenMBS

Danke für die Tipps! Schau ich mir an.

Schade, dass die MBS Funktion nur für macOS funktioniert.

Zum Problem:
Mein Programm merkt sich die Fensterpositionen der verschiedenen Fenster auch für den nächsten Start. Nutzt jemand nun mehr als einen Monitor (Laptop und Zusatzbildschirm), ist es verständlich, wenn man einige Fenster auf dem externen Gerät anzeigen lässt. Wenn man nun den Laptop mobil nutzt und das Programm startet, wird das Fenster an einer Position geöffnet, die nicht im Sichtfeld des Laptops ist oder man nicht an die Titelzeile zum Verschieben kommt.

Das Problem kennen wir sehr gut. Im Office mit 2-4 Monitoren und dann im Home Office mit 1-2 Monitoren…
Unter Windows konnte ich es nie zu 100% lösen und habe es dann aufgegeben. :frowning:

Ja, auch ich hatte mich mehrfach daran versucht. Zuletzt habe ich mich dann auf einen Monitor beschränkt. Ging lange gut. Jetzt hat sich jemand gemeldet und nachgefragt, ob ich hier nachbessern kann.
Ich habe die Routine von Beatrix mal an meinen Code angepasst und es sieht hier bei mir aus wie immer :slight_smile:
Ich werde das mal zur Begutachtung an den Anwender weitergeben.

Danke für die Unterstützung!

1 Like

Ein anderes Problem ist, daß nicht mehr angeschlossene Monitore trotzdem in den System-Voreinstellungen noch vorhanden sind. Damit können Fenster, die an so einem Monitor waren, “verschwinden”. Dafür habe ich ein Menutiem im Windows-Menü “Fenster einsammeln”:

for currentWindow as Integer = 0 to App.WindowCount
  dim ScreenID as Integer = getScreenID(App.Window(currentWindow))
  if ScreenID = -1 then
    Continue
  ElseIf ScreenID > 0 then
    'center window on middle of screen 1
    App.Window(currentWindow).Left = (Screen(0).AvailableWidth - App.Window(currentWindow).Width) / 2
    App.Window(currentWindow).Top = (Screen(0).AvailableHeight - App.Window(currentWindow).Height) / 2
  end if
  
next

Private Function getScreenID(theWindow as Window) As Integer
  
  'set the rect
  if theWindow = Nil or not theWindow.Visible then Return -1
  dim theRect as Realbasic.Rect
  dim ToolbarHeight as Integer = theWindow.Bounds.Height - theWindow.height + 1
  if ToolbarHeight = 1 then Return -1'going FullScreen
  theRect = new REALbasic.Rect(theWindow.Left, theWindow.Top, theWindow.Width, theWindow.Height)
  
  'Find screen.
  Dim screenID as integer
  For l as integer = 0 to screenCount - 1
    if theRect.top >= screen(l).top and theRect.center.x > screen(l).left and theRect.center.x < (screen(l).left + screen(l).width) then screenID = l
  next
  
  Return screenID
    
End Function

Was helfen könnte wenn Du die Einstellungen je nach Monitor Anzahl speicherst und Geräte Name.
Oder auch die Monitor Auflösung dabei.
Einfach nur die Position reicht nicht wie Du gemerkt hast.

Windows mit Multi-Monitor und v.a. verschiedenen DPI ist mühsam. Xojo’s Methoden funktionieren da nur unzuverlässig.
Daher machen wir dies unter Windows mit Declares, um die Systemfunktionen zu nutzen.
Beispielprojekt: Monitors

Der Button ‘Fit on Monitor’ solle das Anliegen hier ermöglichen. Die anderen Buttons (rechts) helfen mit Positionierung von Fenstern und sollte mit MultiMonitor/DPI zurechtkommen.

1 Like

Da sollte das Fenster auf keinem Screen zu finden sein. Dann müsste man ScreenID mit -1 vorbelegen und abschließend bei ScreenID=-1 die Fensterposition auf den Hauptbildschirm legen.
Muss ich mal testen.

ach, da brauche ich ja erst mal zwei Bildschirme :slight_smile:
Muss ich mir mal Hardware ausleihen.

@Jürg_Otter:
An verschiedene DPI-Werte auf unterschiedlichen Monitoren hatte ich noch gar nicht gedacht :frowning:
Ohne Zweitbildschirm macht das eigentlich keinen Spaß, dafür eine Lösung zu bauen.
So richtig Lust habe ich dazu nicht. Mal sehen, was die kommenden Tage noch so ansteht.

Danke für die Tipps!

1 Like