Formulare

Wie manipuliere ich die Form eines Formulars ( z. B. Formular als Kreis )?

Dafür gibt es die sogenannten "Regions":


procedure TForm1.FormCreate(Sender:TObject);
var HR: HRgn;
      n:array[0..3] of TPoint;
begin
  n[0]:=Point(Width div 2,1);
  n[1]:=Point(1, Height div 2);
  n[2]:=Point(Width div 2,Height);
  n[3]:=Point(Width, Height div 2);

  HR:= CreateEllipticRgn (0, 0, Width, Height);
  {oder eine Raute:
  HR:= CreatePolygonRgn(n, 4, Alternate);}

  SetWindowRgn(Handle, HR, True);
end;

Dieses Beispiel hat Michael Schüle in dclpd gepostet. Die Anregung dazu hat er wohl dem Buch "Borland Delphi 3 für Profis" von Walter Doberenz und Thomans Kowalski aus dem Hanser Verlag entnommen.

Applications running in different resolutions

1. I belive I have found the answer to a lot of peoples questions (mine included) about Applications that run in different resolutions.

The problem is if you develop an Application in one resolution, say 1024x768 using Large fonts, then try and run it at say 800x600 using Small fonts. Labels get chopped and components are different sizes than when designed. Other weird looking things happen too.

Well, I found that by changing the PITCH property on the FONT to VARIABLE instead of DEFAULT that it looks the same in every resolution.

This should be done to every component and to the Form itself. (Does anyone know where "Default" is set?)

2. After much experimenting, it appears that delphi figures some font size and scaling factors at design time, and doesn't re-calculate them at run time. This seems to cause some of the "special effects" at different resolutions (i.e. edit boxes with only half of the text visible, and labels partly chopped off).

To get around this, make delphi re-calculate these values, by simply assigning the main form's font at run time (in the oncreate event), as well as any other controls in which you didn't use the ParentFont option.
I think calling the Font's OnChange event will correct the problem as well, but I haven't tried it yet. I sincerely wish we could get a difinitive answer from borland, or someone very knowledgeable on this topic.

On a side note, if I tried to re-assign PixelsPerInch, or the scaled properties at run time, I got a general protection fault (even the example code in the help file gave a GPF).

Code-Schnipsel dafür:

Auf jeden Fall habe ich mal ein Stueck Code dafuer gekriegt, das zu meiner grossen Ueberraschung bis jetzt jedes Formular mitsamt allem Geraffel drauf prima skaliert hat. Es sind nur ein paar Zeilen im FormCreate des Haupt- formulars und dazu zwei Konstanten (global definiert):


const ScreenWidthDev  = XXX;
         ScreenHeightDev = YYY;
{statt XXX und YYY die Aufloesung zur Entwicklungszeit eintragen. 
Angeblich soll der Code am besten von der hoechsten Aufloesung 
runterskalieren. Ich musste aber immer von 640/480 (die hohen 
Aufloesungen kommen bei mir nicht so gut) hochskalieren und es 
ging auch.}

procedure TForm1.FormCreate(Sender: TObject);
var x,y: Integer; // f. Bildschirmauflösung
begin
  Scaled:= true;
  x:= Screen.Width;
  y:= Screen.Height;
  if (x<>ScreenWidthDev) or (y<>ScreenHeightDev) then begin
    Form1.Height:= (Form1.ClientHeight*y div ScreenHeightDev) +
                    Form1.Height - Form1.ClientHeight;
    Form1.Width:= (Form1.ClientWidth*y div ScreenWidthDev) +
                   Form1.Width - Form1.ClientWidth;
    ScaleBy(x,ScreenWidthDev);
  end; // of if

Worueber ich mich immer wieder wundern kann: Mit dieser Methode werden ALLE Fenster des Projekts skaliert, obwohl doch eigentlich ausdruecklich nur Form1 skaliert wird. Komisch.

Ein Fenster einer Anwendung immer zuoberst anzeigen, auch bei minimiertem Hauptfenster

Manchmal möchte man, daß geöffnete (Unter-)Fenster einer Anwendung auf dem Desktop bleiben, wenn das Hauptfenster minimiert wird, oder daß ein Fenster immer im Vordergrund bleibt, auch wenn es nicht den Fokus hat.

Ich will mal kurz zeigen, wie man das zur Laufzeit einstellen kann:


//OnTop..
SetWindowPos(Handle, HWND_TOPMOST, Left,Top, Width,
             Height, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);
//..und zurück:
SetWindowPos(Handle, HWND_NOTOPMOST, Left, Top, Width,
             Height, SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

//OnDesktop..
SetWindowLong(Handle, GWL_HWNDPARENT, 0);
//..und zurück:
SetWindowLong(Handle, GWL_HWNDPARENT, Application.Handle);
FormStyle dabei auf fsNormal setzen. Das ist alles! (Ralph Stoesser)

Wie kann ich ein Fenster transparent darstellen?

Zwei einfache Tricks, um ein Fenster "unsichtbar", also transparent zu zeichnen:

1. So kann man die Transparenz zur Laufzeit umschalten:


Procedure MakeWindowTransparent (Form: TForm);
Var CurrentStyle : LongInt;
Begin
  Form.Visible := False;
  CurrentStyle := GetWindowLong(Form.Handle, GWL_EXSTYLE);
  SetWindowLong(Form.Handle, GWL_EXSTYLE, CurrentStyle Or WS_EX_TRANSPARENT);
  Form.Visible := True;
End; {Paul Röttgen}

Procedure MakeWindowOpaque (Form: TForm);
Var CurrentStyle : LongInt;
Begin
  Form.Visible := False;
  CurrentStyle := GetWindowLong (Form.Handle, GWL_EXSTYLE);
  SetWindowLong(Form.Handle, GWL_EXSTYLE, CurrentStyle And Not WS_EX_TRANSPARENT);
  Form.Visible := True;
End; {Paul Röttgen}

2. So wird ein Fenster transparent erstellt:


procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.Brush.Style := bsClear;
  Form1.BorderStyle := bsNone;
end;
Allerdings sorgt dieses Beispiel nur dafür, daß beim Zeichnen des Fensters der Hintergrund nicht übermalt wird. Soblad das fenster verschoben wird oder der Hintergrund sich ändert, ist der Anschein der Transparenz dahin.

Wie erzeuge ich ein Formular ohne Titelleiste?

1. Möglichkeit:
TForm.BorderStyle auf bsNone zu setzen. Leider ergibt das ein Formular, das dann gar keine Begrenzung mehr hat. Abhilfe schafft ein TBevel, dessen Align man auf alClient setzt.

2. Möglichkeit:
Die Methode CreateParams überschreiben, in der der Parameter-Record für die Fenstererzeugung initialisiert wird:


{ Private Deklaration }
procedure CreateParams(var Params : TCreateParams); override;
...
{ Implementation: }
procedure TForm1.CreateParams(var Params : TCreateParams);
begin
  Inherited Createparams(Params);
  with Params do
    Style := (Style or WS_POPUP) and not WS_DLGFRAME;
end;
Diese Kombination hat den Effekt, daß die Titelleiste entfernt wird, der Begrenzungsstil aber den eingestellten Wert behält.

3. Möglichkeit:
In der OnCreate-Methode des Formulars die API-Funktion "SetWindowLong" aufrufen:


procedure TForm1.FormCreate(Sender: TObject);
begin
  SetWindowLong(Handle, GWL_STYLE, GetWindowLong(Handle, GWL_STYLE)
                              and not WS_CAPTION);
  ClientHeight:=Height;
end;
Um ein Formular ohne Titelleiste noch mit der Maus verschieben zu können, muß man diesem einen Klick auf die (nicht vorhandene) Titelzeile vorgaukeln, wenn der Anwender auf eine beliebige Stelle im Formular klickt. Dazu fügt man folgenden Code in die "OnMouseDown"-Methode des Formulars ein:

if ssLeft in Shift then begin
  ReleaseCapture;
  Self.Perform(WM_NCLBUTTONDOWN, HTCAPTION, varEmpty);
end;

Mit der Enter-Taste den Fokus auf das nächste Control setzen

Um nach Betätigen der Enter-Taste zum nächsten Control auf einem Formular zu wechseln, muß man zuerst die "KeyPreview"-Eigenschaft des Formulars auf "true" setzen. Anschließend kann man in der OnKeyPress-Methode des Formulars auf die Enter-Taste reagieren:


procedure TMainForm.FormKeyPress(Sender: TObject; var Key: Char);
begin
  if Key = #13 then begin   {#13 = Enter}
    Key := #0;
    PostMessage(Handle, WM_NextDlgCtl, 0, 0);
  end;
end;
Bemerkung: Das funktioniert nicht mit einem DBGrid, weil das nächste Feld dort kein separates Objekt darstellt.

Welche Ereignisse werden beim Erstellen und Anzeigen eines Formulars ausgelöst?

Folgende Ereignisse werden in dieser Reihenfolge abgefeuert:

Taskbareinträge auch für untergeordnete Formulare anzeigen

Mit der API-Funktion "SetWindowLong" kann man den Fensterstil so einstellen, daß auch für untergeordnete Dialogfenster eines Programms Einträge in der Windows-Taskbar erscheinen:


procedure TForm2.FormShow(Sender: TObject);
begin
  SetWindowLong(Handle, GWL_ExStyle, WS_Ex_AppWindow);
end;
Im Abschnitt "Applikationen" der Delphi Fundgrube erfährt man, wie man ein Programm ganz ohne Taskbareinträge starten kann.

Ein Fenster zum obersten Fenster (Topmost) auf dem Desktop machen

Mit welchem API-Aufruf kann ich ein Fenster zum Vordergrundfenster machen (also auch gegenüber Fenstern von anderen Prozessen), so als würde FormStyle auf fsStayOnTop stehen?

Mit der API-Funktion "SetWindowPos" bestimmt man unter anderem auch die Position eines Fensters in der Z-Ordnung:


{Fenster nach vorne setzen:}
SetWindowPos(Handle,
             HWND_TOPMOST,
             Left,Top, Width,Height,
             SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);

{..und wieder zurück:}
SetWindowPos(Handle,
             HWND_NOTOPMOST,
             Left, Top, Width,Height,
             SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE);