In der IT-Welt ist der technische Fortschritt sicher nichts Neues. Dieser findet in allen Bereichen statt, nicht nur bei der unterschiedlichsten Hardware, sondern auch bei den Bildschirmauflösungen. Anfang der neunziger Jahre lag die am weitesten verbreitete Auflösung bei 640×480 Pixeln. Ende des Jahrzehnts lag diese bereits bei 800×600 Pixel. Die Auflösung erhöhte sich im Laufe der Jahre weiter von 1024×768 bis zur akutellen Darstellung von 1366×768 Pixel. Infolgedessen gab es beim Support in der Vergangenheit vermehrt Anfragen, wie eine individuelle Skalierbarkeit eines Frames in conzept 16 umgesetzt werden kann. Im folgenden Artikel möchten ich Ihnen eine Prozedur vorstellen, welche einen einfachen Weg bietet, vorhandene Frames individuell zu skalieren.
Die Grundidee:
Meist arbeiten die Anwender im Desktopbereich mit den üblichen Auflösungen 1024 x 768, 1366 x 768, 1280 x 1024 und 1920 x 1080.
Anstatt nun den zugrunde liegenden Dialog zur Laufzeit zu skalieren, werden für die bekannten Auflösungen skalierte Dialoge generiert und mit WinSave()
in der Datenbank gespeichert. Wenn dann der Dialog in der Anwendung angezeigt werden soll, wird zunächst die Auflösung des Bildschirms bestimmt und anschließend der vorgenerierte Dialog geladen. Dies kann mit den Standard conzept 16-Befehlen WinInfo()
und WinDialog()
erreicht werden. Bliebe noch die Aufgabe der Skalierung, die Gegenstand des vorliegenden Artikels ist.
Main-Funktion:
Innerhalb dieser Funktion wird der bereits existente, zu skalierende Frame übergeben. Als nächstes kann nun die gewünschte Größe angegeben werden. Hier ist zu empfehlen, dass das Seitenverhältnis des skalierten Frames identisch zum Ausgangsdialog ist, da es sonst zu einer nicht gewünschten Darstellung, von beispielsweise Text-Objekten inklusive Schrift, kommen kann. Nach der Eingabe der gewünschten Framegröße wird nun die eigentliche Skalierungsfunktion aufgerufen.
main()
local
{
tDHdl : handle; // Dialog
tSizeWish : point; // gewünschte Dialoggröße
}
{
// zu skalierender Dialog
tDHdl # WinOpen('DragDropEvents', _WinOpenDialog | _WinOpenEventsOff);
if (tDHdl > 0)
{
tDHdl->wpAreaClientRestore # false;
// Wenn die Neuen Icons verwendet werden, dann setzen
//_App->wpTileTheme # _WinTileThemeEnhanced;
// Wunschgröße des Dialogs
tSizeWish # PointMake(1024 , 768);
// Skalierungsfunktion
ScaleFrame(tDHdl, tSizeWish:x, tSizeWish:y);
tDHdl->WinDialogRun(_WinDialogCenterScreen);
tDHdl->WinClose();
}
}
Skalierungsfunktion ‘ScaleFrame’:
Dieser Funktion wird der Ausgangsframe, die gewünschte Breite und Höhe übergeben. Zunächst wird die aktuelle Höhe und Breite des Frames und die des Clientbereichs ermittelt. Im Anschluss daran wird nun die Differenz des Clientbereichs des skalierten Dialogs berechnet. Um die Skalierung des Frames durchzuführen, muss der Skalierungsfaktor ermittelt werden, hierfür ist es unerlässlich die prozentuale Abweichung der Höhe und Breite festzustellen. Dies wird durch die Funktion GetDifferencePercent()
bewerkstelligt. Ist der Skalierungsfaktor ermittelt worden, so wird der aktuelle Frame auf die gewünschte Größe gesetzt und im Anschluss daran sämtliche Objekte und deren Unterobjekte skaliert.
sub ScaleFrame
(
aFrame : handle; // Frame
aWidth : int; // gewünschte Width
aHeight : int; // gewünschte Height
)
local
{
tWidth : int; // Width des Frames
tHeight : int; // Height des Frames
tClientW : int; // Clientbereich Width
tClientH : int; // Clientbereich Height
tDifW : int; // Width Differenz (Dialogrand und Clientbereich)
tDifH : int; // Height Differenz (Dialogrand und Clientbereich)
tScaleClientW : int; // Clientbereich des skalierten Frames (Width)
tScaleClientH : int; // Clientbereich des skalierten Frames (Height)
tPercentW : float; // Width Skalierungsfaktor in %
tPercentH : float; // Height Skalierungsfaktor in %
}
{
// Width und Height des Frames
tWidth # aFrame->wpAreaRight - aFrame->wpAreaLeft;
tHeight # aFrame->wpAreaBottom - aFrame->wpAreaTop;
// Clientbereich
tClientW # WinInfo(aFrame, _WinClientWidth);
tClientH # WinInfo(aFrame, _WinClientHeight);
// Differenz zwischen Frame- und Clientbereich
tDifH # tHeight - tClientH;
tDifW # tWidth - tClientW;
// Clientbereich des skalierten Frames
tScaleClientW # aWidth - tDifW;
tScaleClientH # aHeight - tDifH;
// prozentuale Abweichung (Width)
tPercentW # GetDifferencePercent(tClientW, tScaleClientW);
// prozentuale Abweichung (Height)
tPercentH # GetDifferencePercent(tClientH, tScaleClientH);
// Faktor zum skalieren
tPercentW # tPercentW / 100.0;
tPercentH # tPercentH / 100.0;
// Framegröße
aFrame->wpAreaLeft # 0;
aFrame->wpAreaTop # 0;
aFrame->wpAreaRight # aWidth;
aFrame->wpAreaBottom # aHeight;
// Objekte und Unterobjekte skalieren
aFrame->ScaleObject(tPercentW, tPercentH, tClientW, aWidth, aHeight);
}
Funktion ‘ScaleObject’:
Nach der Übergabe des Parent-Objektes, des Skalierungsfaktors der Länge und Breite, des Clientbereichs und der gewünschten Breite und Länge, wird zuerst der Skalierungsfaktor des Fonts ermittelt. Im Anschluss daran erfolgt eine Größenanpassung des Textes der Objekte. Als nächsten Schritt werden nun innerhalb einer Schleife alle Unterobjekte ermittelt und überprüft, ob es sich hierbei nicht um Ausnahmen handelt. Für jedes ermittelete Unterobjekt wird nun die Funktion rekrusiv aufgerufen um ebenfalls eine Größenanpassung des Fonts durchführen zu können. Als finaler Schritt wird am Ende der Funktion jedes einzelne Objekt in seiner Größe um den vorher ermittelten prozentualen Anteil vergrößert.
// Objekte skalieren
sub ScaleObject
(
aParent : handle; // Parent-Objekt
aPercentW : float; // Skalierungsfaktor Width
aPercentH : float; // Skalierungsfaktor Height
aWidth : int; // Clientbereich des alten Frames
aNewWidth : int; // Wunschdialog Width
aNewHeight : int; // Wunschdialog Height
)
local
{
tObj : handle; // Objekt
tArea : rect; // Größe
tGrouping : int; // Grouping-Eigenschaft
tHasGrouping : logic; // Grouping gesetzt?
tHasFont : logic; // besitzt ein Font?
tFontParent : logic; // FontParent gesetzt?
tFont : font; // Font des Objekts
tFontPercent : float; // Skalierungsfaktor der FontSize
tPoint : float; // FontSize
}
{
// ist Grouping gesetzt?
if (WinPropGet(aParent, _WinPropGrouping, tGrouping))
tHasGrouping # tGrouping != _WinGroupingNone;
// Skalierungsfaktor des Fonts
tFontPercent # Fnc.CalcPercent(aWidth, aNewWidth, aNewHeight);
// Text in den Objekten skalieren
if (WinPropGet(aParent, _WinPropFontParent, tFontParent)) // Eigenschaft vorhanden?
{
if (!tFontParent) // false
{
tFont # aParent->wpFont;
// FontSize liegt in zehntel point vor
tPoint # CnvFI(tFont:Size) / 10.0;
// Font skalieren
tPoint # Fnc.CalcPoint(tPoint, tFontPercent);
tFont:Size # CnvIF(tPoint) * 10;
aParent->wpFont # tFont;
}
}
// Objekte suchen
for tObj # WinInfo(aParent, _WinFirst);
loop tObj # WinInfo(tObj, _WinNext);
while (tObj > 0)
{
// Ausnahmen
if (WinInfo(tObj, _WinType) = _WinTypeListColumn or
WinInfo(tObj, _WinType) = _WinTypeGroupColumn or
WinInfo(tObj, _WinType) = _WinTypeTreeNode or
WinInfo(tObj, _WinType) = _WinTypeToolbarButton or
WinInfo(tObj, _WinType) = _WinTypeStatusbar)
cycle;
// Unterobjekte suchen
tObj->ScaleObject(aPercentW, aPercentH, aWidth, aNewWidth, aNewHeight);
// Ausnahme
if (WinInfo(tObj, _WinType) = _WinTypeGroupTile)
cycle;
// Ausnahme
if (tHasGrouping)
if (WinPropGet(tObj, _WinPropAlignGrouping, tGrouping) and tGrouping != _WinAlignGroupingNone)
cycle;
// skalieren der Objekte
tArea # tObj->wpArea;
tArea:Left # CnvIF(CnvFI(tArea:Left) * aPercentW);
tArea:Top # CnvIF(CnvFI(tArea:Top) * aPercentH);
tArea:Right # CnvIF(CnvFI(tArea:Right) * aPercentW);
tArea:Bottom # CnvIF(CnvFI(tArea:Bottom) * aPercentH);
tObj->wpArea # tArea;
}
}
Ausnahmen
Innerhalb von conzept 16 existieren allerdings auch Objekte, welche nicht skaliert werden können. So wird der Spaltenkopf einer Listen-Objektes nicht in seiner Größe angepasst. Auch Checkbox- und Radiobutton-Objekte, sowie Scrollbox-Objekte erfahren keine Skalierung. Gegenwärtig bestehen darüber hinaus noch weitere Punkte, welche vor der Skalierung von Frames beachtet werden sollten, damit ein einwandfreies Ergebnis erreicht wird:
- die Eigenschaft
wpAreaClientRestore
darf beim Frame nicht gesetzt werden.
Nachdem der Frame skaliert und gespeichert wurde kann die Eigenschaft wieder gesetzt werden. - Es muss beachtet werden, dass durchgehend die gleiche
wpTileTheme
Eigenschaft verwendet wird. - Sämtliche Objekte sollten einen gewissen Abstand zum Frame-Rand aufweisen.
- Die Eigenschaft
wpShowGrip
beimToolbar-Button
sollte gesetzt sein.
Es könnte sonst passieren, dass derToolbar-Button
seine bisherige Position ‘verändert’. - Der Text der
Labels
sollte nicht über Rand hinaus gehen. - Der Font des
RtfEdit
-Objektes sollte prozedural nicht geändert werden.
Die im Artikel vorgestellte Prozedur steht am Ende des Artikel als Download bereit.
Eine Antwort
Wenn der User das Skalieren der Fensterinhalte "on the fly" haben will d.h. wenn er ein Fensterskaliert, kann man das auch in der EvtPosChanged machen. Dann sollte man sich nur die Urpsrungsgrößen der Objekte merken (CteTree) und immer mit diesen rechnen. Skaliert man mit den bereits veränderten Werten, ergeben sich mit jeder neuen Skalierung Rundungsfehler, die das Aussehen dann irgendwann total zerstören.