1.Jak zrobić pasek
gradientowy?
gradient, tło, instalator
Należy narysować wiele prostokątów (poziomo lub pionowo) stopniowo zmieniając
im kolor. Np.:
procedure TForm1.FormPaint(Sender: TObject);
const N=100;
var Y:Integer;
Cl:TColor;
begin
for Y:=0 to N-1 do
with Canvas do
begin
Cl:=RGB(0,0,Round(50+205*(Y/N)));
Pen.Color:=Cl;
Brush.Color:=cl;
Rectangle(0,Round(ClientHeight*(Y/N)),ClientWidth,Round(ClientHeight*((Y+1)/N)));
end;
end;
Spowoduje to dodanie do formy tła jakie często występuje w programach
instalacyjnych. Aby nie występowały problemy przy zmianie rozmiarów formy należy
dodać jeszcze poniższy kod:
procedure TForm1.FormResize(Sender:
TObject);
begin
Invalidate;
end;
2.Jak przejść z jednego komponentu TEdit
do drugiego przy pomocy Entera (domyślnie przechodzi się przy pomocy
Tab)?
Tab, Enter, TEdit, klawisz
Należy zmienić obsługę klawisza Enter w każdym z komponentów. Przykładowy
kod:
procedure TForm1.Edit1KeyPress(Sender: TObject; var
Key: Char);
begin
if Key=#13 then
begin
Perform(wm_NextDlgCtl,0,0);
Key:=#0;
end;
end;
Do każdego komponentu TEdit należy podstawić powyższą procedurę jako obsługę
zdarzenia OnKeyPress.Można to zrobić klikając na formie z wciśniętym
klawiszem Shift na każdym komponencie TEdit a następnie w okienku
ObjectInspector klikając podwójnie na polu OnKeyPress (w okienku
nie będzie widoczna nazwa komponentu).
Krzysztof Świątkowski zwrócił mi
uwagę na trochę odmienne podejście. Zamiast powyższego dodajemy do formy
obsługę:
procedure TForm1.FormKeyUp(Sender: TObject; var
Key: Word;
Shift: TShiftState);
begin
if (Key=VK_RETURN) and ([ssCtrl,ssShift]*Shift=[]) then
Perform(WM_NEXTDLGCTL,0,0);
end;
Dodatkowo ustawiamy właściwość formy KeyPreview na True. Wtedy
Enter działa jak Tab na całej formie a nie tylko wybranych kontrolkach.
Źródło informacji: Krzysztof
Świątkowski.
3.Gdzie można znaleźć archiwum grupy
pl.comp.lang.delphi?
archiwum,
pl.comp.lang.delphi
Na stronie DejaNews znajduje się
archiwum wszystkich grup dyskusyjnych. Korzystając z tamtejszej wyszukiwarki
należy zdefiniować filtr obejmujący szukaną grupę. Można też ściągnąć archiwum
grupy wraz z przeszukiwarką z mojej strony.
4.Gdzie można znaleźć informacje i
nagłówki do DirectX?
DirectX, Blake Stone, DelphiX,
DelphiJedi
Informacje o DirectX oraz pliki nagłówkowe w formacie *.H (do języka C) można
znaleźć na stronach firmy Microsoft dotyczących Microsoft Software Development Network.
Jeśli jesteś tam po raz pierwszy to będziesz musiał się zarejestrować (jest to
bezpłatne). Czasem można znaleźć DirectX SDK (Software Development Kit) na
płytach CD dołączanych do czasopism komputerowych. Przetłumaczone pliki
nagłówkowe znajdują się na stronach Blake'a
Stone chociaż trudno jest się tam dostać. Mirror nagłówków prowadzi
również Radosław Przybył. Na DSP znajduje się również biblioteka
DelphiX znacznie ułatwiająca pisanie programów pod DirectX. Warto też zajrzeć na
strony projektu JEDI.
5.Co to jest DSP?
DSP, sunsite.icm.edu.pl
Delphi Super Page prowadzona
jest przez Roberta Czerwińskiego na
serwerze ICM. Jest to jedna z największych (o ile nie największa) biblioteka
komponentów do Delphi, C++Buildera i JBuildera na świecie. Jeśli czegoś nie ma
na DSP to raczej małe są szanse, że w ogóle istnieje :-). DSP ma również wiele
mirrorów poza Polską.
6.Co się stało z procedurą Delay z
TurboPascala? Jak mam zrobić w Delphi pauzę?
Delay,
pauza
Nie ma w Delphi zaimplementowanej procedury Delay. Można jako
jej zamiennika użyć funkcji WinAPI o nazwie Sleep. Powoduje ona
zawieszenie wykonania programu na określoną liczbę milisekund. Jednakże w tym
czasie Twoja aplikacja nie będzie mogła obsługiwać komunikatów Windows. Dlatego
też czasem lepszym rozwiązaniem jest użycie takiego kodu:
procedure
TForm1.Button1Click(Sender: TObject);
var Teraz:TDateTime;
begin
// Tu wstawiamy operacje wykonywane przed pauzą
Teraz:=Now;
repeat
Application.ProcessMessages; // Pozwalamy aplikacji
obsłużyć komunikaty
until Teraz+5/SecsPerDay<Now; // 5 to liczba sekund pauzy
// Tu operacje wykonywane po pauzie
end;
Należy pamiętać o ważnej rzeczy: powyższy kod nie gwarantuje że inne
procedury obsługi zdarzeń nie zostaną wykonane a tylko, że wykonanie kodu
tej procedury zostanie wstrzymane na kilka sekund.
7.Jak drukować tekstowo w
Delphi?
drukowanie, tekst
Należy korzystać z funkcji WinAPI operujących na drukarkach:
uses
WinSpool,Printers;
procedure TForm1.Button1Click(Sender: TObject);
var Size,n:Integer;
H:THandle;
Info:PAddJobInfo1;
F:TextFile;
sPrinterName,sDriver,sPort:array[0..255]of
Char; // sDriver i sPort nie będą
// wykorzystane
begin
Printer.GetPrinter(sPrinterName,sDriver,sPort,h);
OpenPrinter(sPrinterName,H,nil);
try
AddJob(H,1,nil,0,Size); // pobranie rozmiaru bufora
GetMem(Info,Size);
try
// Poniższa funkcja zwraca nam nazwę pliku do którego możemy zapisywać
AddJob(H,1,Info,Size,n);
// Tutaj zapisujemy do pliku
AssignFile(F,Info^.Path);Rewrite(F);
try
Writeln(F,'Hello world!');
Writeln(F,'To jest test drukowania
tekstowego...');
finally
CloseFile(F);
end;
// Wrzucamy plik do kolejki drukowania, potem Windows go skasuje
ScheduleJob(H,Info^.JobId);
finally
// Zwalniamy pamięć...
FreeMem(Info,Size);
end;
finally
// ...i drukarkę
ClosePrinter(H);
end;
end;
Można też spróbować innego sposobu. Użyć CreateFile aby otrzymać uchwyt do
LPT1:
LPTHandle:=CreateFile('LPT1',GENERIC_WRITE,0,PSecurityAttributes(nil),
OPEN_EXISTING, FILE_FLAG_OVERLAPPED,0);
Następnie użyć WriteFile aby wysłać kolejne znaki lub:
while not TransmitCommChar(LPTHandle,CharToSend) do Application.ProcessMessages;
Powyższy kod wysyła kolejne znaki na port równoległy za każdym razem czekając
na obsłużenie znaku przez drukarkę.
Źródło informacji: Tomasz Pytlik, Krzysztof Świątkowski, Chris Monson
8.Jak wywołać domyślny program pocztowy z
wpisanym już adresem odbiorcy?
email, adres,
poczta
Należy skorzystać z funkcji WinAPI ShellExecute na przykład w ten
sposób:
uses ShellApi;
procedure TForm1.Button1Click(Sender: TObject);
begin
ShellExecute(Handle,'open','mailto:wieczor@polbox.com','','',sw_Normal);
end;
Oprócz samego nadawcy można też podać tytuł i treść listu umieszczając jako
argument ShellExecute następujący tekst:
mailto:s_dusza@koti.com.pl?subject=test&body=Tu+jest+tresc
W podobny sposób można otworzyć okno Exploratora Windows podając nazwę
katalogu a także wywołać aplikację obsługującą dany format pliku.
Marcin Qfel Zaleski podesłał kod krzystający z funkcji MAPI. Dzięki MAPI
można w pełni kontrolować proces wysyłania poczty, w szczególności dodać do
listu plik jako załącznik:
procedure cos_tam;
var
MAPIFileDesc : TMAPIFileDesc;
MAPIMessage : TMAPIMessage;
MAPIRecipDesc : TMapiRecipDesc;
hMAPIDLL :
THandle;
pfnMAPISendMail : TFNMAPISendMail;
begin
//załadowanie biblioteki
hMAPIDLL := LoadLibrary('MAPI32.DLL');
if hMAPIDLL=0 then
begin
//zle się dzieje
end;
//pobranie adresu funkcji
@pfnMAPISendMail :=
GetProcAddress(hMAPIDLL,'MAPISendMail');
if @pfnMAPISendMail=nil then
begin
FreeLibrary(hMAPIDLL);
//zle się dzieje
end;
//przygotowanie opisu adresata
FillChar(MAPIRecipDesc,SizeOf(TMAPIRecipDesc),0);
with MAPIRecipDesc do
begin
ulRecipClass := MAPI_TO;
lpszName := 'John Smith';
lpszAddress :=
'johnsmith@server.com';
end;
//przygotowanie opisu załącznika
FillChar(MAPIFileDesc,SizeOf(TMAPIFileDesc),0);
with MAPIFileDesc do
begin
nPosition := Cardinal(-1);
lpszPathName := 'C:\Moje
dokumenty\list.doc';
lpszFileName := 'list.doc';
end;
//przygotowanie rekordu wiadomości
FillChar(MAPIMessage,SizeOf(TMAPIMessage),0);
with MAPIMessage do
begin
lpszSubject := 'temat listu';
lpszNoteText := 'tresc listu';
nRecipCount := 1;
lpRecips := @MAPIRecipDesc;
nFileCount := 1;
lpFiles := @MAPIFileDesc;
end;
//wysłanie
if
pfnMAPISendMail(0,Handle,MAPIMessage,MAPI_DIALOG,0)<>SUCCESS_SUCCESS
then
begin
FreeLibrary(hMAPIDLL);
//zle się dzieje
end;
//zwolnienie zasobów
FreeLibrary(hMAPIDLL);
end;
Źródło informacji: Sebastian A.
Dusza, Marcin Qfel
Zaleski.
9.Dlaczego programy napisane w Delphi nie
"fruną" na pasek zadań a po prostu się minimalizują, jak Windows
3.11?
minimalizacja, animacja, Win95, pasek
zadań
Dlaczego, że programiści z Borland Int.
wyłączyli animację okienek. Oddaję głos Krzyśkowi Świątkowskiemu:
"Dlatego że przy minimalizacji chłopcy z Borlanda animację wyłączają, jak się
ją włączy to to głupio wygląda bo tak naprawdę minimalizuje się nie to okienko
co trzeba. Na upartego można to zrobić samemu funkcją API ale nie pamiętam jak
się nazywała."
Dlaczego Borland tak to rozwiązał?
"Żeby można było w każdej chwili wołać funkcje które wymagają uchwytu do okna
Application [Delphi M.W.] tworzy prawdziwe okno główne u siebie. To
okno o którym my mówimy że jest główne (MainForm) jest po prostu widoczne a
prawdziwe okno główne to od kolejki komunikatów aplikacji siedzi w TApplication.
Po zmianie tej funkcji o której wspomniałem widać animację okna głównego, czyli
tego co siedzi w Application a nie głównej formy i dlatego wygląda głupio. Ktoś
kiedyś mówił że na DSP jest komponent który pozwala to jako obejść. Ja znalazłem
jedynie obejście w postaci funkcji rysującej animacje ramki okna."
Jak to obejść?
"Przekompilować unit Forms tam jest jakaś taka funkcyjka która wyłącza
animacje, jak chcesz to mogę sprawdzić bo gdzieś mam chyba stare posty na ten
temat"
Podejrzewam, że Krzyśkowi chodziło o funkcję:
procedure
ShowWinNoAnimate(Handle: HWnd; CmdShow: Integer);
var
Animation: Boolean;
begin
Animation := GetAnimation;
if Animation then SetAnimation(False);
ShowWindow(Handle, CmdShow);
if Animation then SetAnimation(True);
end;
Jest ona wywoływana w kilku miejscach modułu Forms i należałoby ją zmienić
na:
procedure ShowWinNoAnimate(Handle: HWnd; CmdShow: Integer);
begin
ShowWindow(Handle, CmdShow);
end;
W tym miejscu muszę dodać, że dobrze jest zrobić sobie kopię zapasową
wszystkich plików bibliotecznych (PAS, DCU, DPL itp.) przed
rekompilacją bibliotek standardowych.
Suplement
Ostatnio (dzięki Darkowi
Brzezińskiemu) doszły nowe informacje. Aby poprawnie działało
minimalizowanie okien w Windows 95 należy:
W module projektu:
- dodać do uses Windows,
- zadeklarować zmienną np. ES : Integer;
- po Application.Initialize dopisać:
ES:=GetWindowLong(Application.Handle, GWL_EXSTYLE);
ES:=ES or
WS_EX_TOOLWINDOW and not
WS_EX_APPWINDOW;
SetWindowLong(Application.Handle,GWL_EXSTYLE,ES);
Okno z ustawionym stylem WS_EX_TOOLWINDOW nie jest pokazywane na pasku
zadań.
W module głównego formularza aplikacji należy dodać:
procedure
CreateParams(var Params:TCreateParams);override;
procedure WMSysCommand(var Message:TWMSysCommand);message
WM_SYSCOMMAND;
...
procedure TForm1.CreateParams(var Params:TCreateParams);
begin
inherited CreateParams(Params);
with Params do ExStyle:=ExStyle or WS_EX_APPWINDOW;
end;
procedure TForm1.WMSysCommand(var Message:TWMSysCommand);
begin
if (Message.CmdType and $FFF0=SC_MINIMIZE) then
WindowState:=wsMinimized
else inherited;
end;
Ominięcie domyślnej obsługi komunikatu, która wywołuje
Application.Minimize. Po tych zmianach minimalizuje się formularz (z
animacją), a nie ukryte okno aplikacji.
Źródło informacji: Darek
Brzeziński, Krzysztof
Świątkowski
10. Co to znaczy: okienko ładowane
dynamicznie?
forma, ładowanie dynamiczne
Standardowo Delphi tworzy wszystkie formy przy starcie programu (spójrz do
pliku *.DPR). Tak stworzone formy istnieją przez cały czas działania aplikacji i
zasoby przez nie zajmowane zwalniane są dopiero po jej zakończeniu. Przez
większość czasu formy są ukryte i pokazują się dopiero gdy wywołamy procedurę
Show. Aby dynamicznie ładować okienka należy przesunąć je w opcjach
projektu z listy Auto-Create Forms na Available Froms. Potem jeśli
będziemy chcieli skorzystać z okienka dialogowego dynamicznie to możemy to
zrobić na przykład w ten sposób:
procedure
TForm1.Button1Click(Sender: TObject);
begin
Form2:=TForm2.Create(Application);
try
Form2.ShowModal;
finally
Form2.Free;
end;
end;
Widać tu ręczne utworzenie formy-obiektu, jego wywołanie i skasowanie. Z
oknami niemodalnymi jest inaczej bo nie zachowują się one jak "procedury"
(wybaczcie mi ten skrót myślowy). Jeśli chcemy utworzyć okno niemodalne w jednym
egzemplarzu to możemy zrobić to tak:
procedure
TForm1.Button1Click(Sender: TObject);
begin
if not Assigned(Form2)then
Form2:=TForm2.Create(Application);
Form2.Show;
end;
Czyli najpierw sprawdzamy czy już utworzyliśmy formę (jeśli nie to ją
tworzymy) a potem pokazujemy ją na ekranie. Od tej chwili forma żyje własnym
życiem. Jeśli chcemy zwolnić zajmowaną przez nią pamięć gdy użytkownik ją
zamknie to należy oprogramować jej zdarzenie OnClose (zwracam uwagę na
nazwę formy: Form2 a nie Form1):
procedure
TForm2.FormClose(Sender: TObject; var Action:
TCloseAction);
begin
Action:=caFree; // None, Hide, Minimize
Form2:=Nil;
end;
Tu mieliśmy do wyboru: zwolnić pamięć zajmowaną przez formę, nic nie robić
(wtedy nie da się zamknąć takiego okienka), ukryć formę lub ją zminimalizować.
Ostatnia linia jest potrzebna gdyż zwalniana forma nie aktualizuje zmiennej
Form2. W efekcie przy ponownym wywołaniu TForm1.Button1Click
pojawiłby się błąd.
11. Jak sprawdzić w jakim trybie
graficznym działa program?
tryb graficzny,
rozdzielczość ekranu
W module Forms jest zadeklarowany obiekt Screen którego dwie
właściwości Screen.Width i Screen.Height określają rozmiary
ekranu.
12. Jak zapisać do pliku zawartość
komponentu TMemo?
TMemo, plik,
zapisywanie
Skorzystać z metody SaveToFile. Memo ma również kilka innych ciekawych
możliwości:
| TMemo.Lines.SaveToFile |
Zapisuje zawartość memo do pliku tekstowego |
| TMemo.Lines.LoadFromFile |
Ładuje z pliku tekstowego zawartość memo |
| TMemo.Lines.Count |
Podaje liczbę linii tekstu zawartego w memo |
| TMemo.CopyToClipboard |
Kopiuje zaznaczony tekst do schowka |
| TMemo.PasteFromClipboard |
Na odwrót |
| TMemo.SelectAll |
Zaznacza cały tekst w memo |
Właściwość Lines jest typu TStrings (dokładniej pochodzi od
tego typu) i da się z nią zrobić to samo co z obiektem typu TStringList.
Aby skopiować zaznaczony w memo tekst do schowka należy wykonać:
Memo1.CopyToClipboard;
zaś aby zaznaczyć cały tekst w memo:
Memo1.SelectAll;
Po więcej informacji proponuję zajrzeć do helpa.
13. Jak w Delphi wykryć wejście i
wyjście myszki w obszar przycisku?
myszka, przycisk,
wejście, wyjście
Ten problem pojawia się najczęściej przy pisaniu własnych komponentów i
najprościej rozwiązać go właśnie pisząc komponent. Poniżej podaję deklarację
przykładowego komponentu wykorzystującego komunikaty cm_MouseEnter i
cm_MouseLeave generowane przez Delphi do sprawdzenia pozycji myszki (za
uwagi dotyczące tego kodu dziękuję Markowi Parfianowiczowi):
unit
Button1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs,
StdCtrls;
type
TMyButton = class(TButton)
protected
FMouseOver, FMouseOut : TNotifyEvent;
procedure CMMouseEnter(var Message:TMessage);message
cm_MouseEnter;
procedure CMMouseLeave(var Message:TMessage);message
cm_MouseLeave;
published
property OnMouseOver: TNotifyEvent read FMouseOver write
FMouseOver;
property OnMouseOut: TNotifyEvent read FMouseOut write
FMouseOut;
end;
procedure Register;
implementation
procedure TMyButton.CMMouseEnter(var Message:TMessage);
begin
if Assigned(FMouseOver)then OnMouseOver(Self);
Message.Result:=1;
end;
procedure TMyButton.CMMouseLeave(var Message:TMessage);
begin
if Assigned(FMouseOut)then OnMouseOut(Self);
Message.Result:=1;
end;
procedure Register;
begin
RegisterComponents('T-1000', [TMyButton]);
end;
Po dodaniu komponentu do palety możemy już z niego korzystać.
14. Jak zmierzyć długość tekstu w
pikselach a nie znakach?
tekst, TCanvas, długość,
font, czcionka
Należy użyć metody TCanvas.TextWidth('Ala ma kota') podającej szerokość
tekstu właśnie w pikselach na konkretnym urządzeniu (ekranie, drukarce) przy
aktualnie ustawionym foncie.
15. Jak z poziomu Delphi wykonać program
DOSa?
Exec, DOS, program, uruchomić
Należy użyć funkcji WinExec z WinAPI. Na przykład:
procedure
TForm1.Button1Click(Sender: TObject);
begin
WinExec('rar.exe a archiwum *.*',sw_Normal);
end;
Spowoduje to wywołanie programu RAR z odpowiednimi parametrami i utworzenie
przez niego archiwum.
16. Jak obsłużyć komunikat Windows
którego forma nie obsługuje np. wm_NCHitTest?
komunikaty
Należy dopisać w sekcji public:
type
TForm1 = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
procedure WMNCHitTest(var Message:TWMNCHitTest);message
wm_NCHitTest;
end;
zaś w części implementation:
procedure TForm1.WMNCHitTest(var
Message : TWMNCHitTest);
var P:TPoint;
begin
inherited;
P:=ScreenToClient(SmallPointToPoint(Message.Pos));
with Label1,Message do
if (P.X>=Left) and (P.X<Left+Width) and
(P.Y>=Top) and
(P.Y<Top+Height) then
Result:=htCaption;
end;
W tym przypadku powierzchnia etykiety Label1 zachowuje się jak jej
pasek tytułowy. Za poprawki w powyższym kodzie dziękuję Maciejowi "MACiASowi" Pilichowskiemu
17. Jak dostosować wydruk do różnych
drukarek?
drukowanie, drukarka, rozdzielczość
Należy skorzystać z funkcji GetDeviceCaps z WinAPI i z modułu
Printers. Na przykład:
procedure
TForm1.Button1Click(Sender: TObject);
var XD,YD:Integer;
begin
XD:=GetDeviceCaps(Printer.Handle,LogPixelSX); // liczba pikseli na cal w poziomie
YD:=GetDeviceCaps(Printer.Handle,LogPixelSY); // liczba pikseli na cal w poziomie
with Printer,Printer.Canvas do
begin
Title:='Wydruk próbny';
BeginDoc;
try
// Linia w poprzek całej kartki
MoveTo(PageWidth,0);LineTo(0,PageHeight);
// Linia o długości 1 cala
MoveTo(0,0);LineTo(XD,YD);
finally
EndDoc;
end;
end;
end;
To jednak nie koniec. Okazuje się, że NetManiak ma do tego kilka uwag:
"Już znalazłem formułę, dzięki której można dokładnie obliczyć ile musi mieć
pixeli linia, by na drukarce objawiła się jako 1 calowa. Teoretycznie powinno to
być (jak sugeruje kolega BACIK, tudzież dokumentacja windows) LOGPIXELSX i
LOGPIXELSY. Moje doświadczenia wskazują jednakże, iż rzeczywista wartość wynosi:
w poziomie: LOGPIXELX * PHYSICALWIDTH / HORZRES
w pionie: LOGPIXELSY *
PHYSICALHEIGHT / VERTRES
gdzie LOGPIXELX - wynik funkcji GetDeviceCaps(LOGPIXELX ) itd...
Sprawdziłem to na 2 drukarkach: Cannon BJC4300 i HP (atramentówka, A4,
oznaczenia nie pamiętam)."
Źródło informacji: Adam K.
"NetManiak".
18. Jak sprawić aby dymki z
podpowiedziami nie znikały?
dymki, hint
Należy ustawić HintHidePause na dość dużą wartość:
Application.HintHidePause:=100000;
19. Mam problem z przesiadką z Delphi
1.0 na Delphi 2.0. Pliki binarne zapisywane przez program po rekompilacji
przestały się wczytywać.
błędy odczytu, plik,
rekordy, record
Problemem może być zarówno zmiana wielkości typu Integer (teraz jest 4
bajtowy czyli dawne Longint) jak i wyrównywanie przez Delphi zmiennych w pamięci
do adresów podzielnych przez 4. Na to pierwsze pomoże zmiana typów zmiennych w
programie z Integer na SmallInt (które jest 2 bajtowe). Aby obejść ten drugi
problem trzeba albo wyłączyć wyrównywanie zmiennych w ustawieniach kompilatora
(ale spowolni to program) albo rekordy zapisywane na dysk zadeklarować ze
słówkiem packed co lokalnie wyłączy wyrównywanie zmiennych.
20. Jak załadować bitmapę z zasobów pod
Delphi 1.0?
bitmapa, zasoby, ładowanie
Skorzystaj z funkcji LoadBitmap:
Image.Picture.Bitmap.Handle:=LoadBitmap(hInstance,'NAZWA_BITMAPY');
21. Jak sprawdzić gdzie znajduje się
mysz?
myszka, pozycja, ekran
Pozycję myszy (we współrzędnych ekranowych) podaje funkcja
GetCursorPos.
22. Dlaczego nie działa
StretchDraw dla ikon?
ikony, StretchDraw,
rysowanie
Niedoróbka Delphi. Aby narysować rozciągniętą ikonę należy skorzystać z
funkcji:
DrawIconEx(Canvas.Handle, 0, 0, Icon.Handle, szerokosc, wysokość,
0, 0,DI_NORMAL);
23. Jak zrobić listę otwartych okien w
Windows?
lista okien, Windows, pulpit, pasek
zadań
Oto przykładowy kod wykorzystujący funkcje WinAPI:
function
EnumWindowsProc(WHandle: HWND; LParM: LParam):
Boolean;StdCall;Export;
var Title,ClassName:array[0..128] of char;
sTitle,sClass,Linia:STRING ;
begin
Result:=True;
GetWindowText(wHandle, Title,128);
GetClassName(wHandle, ClassName,128);
sTitle:=Title;
sClass:=ClassName;
if IsWindowVisible(wHandle) then
begin
Linia:=sTitle+'
'+sClass+'
'+IntToHex(wHandle,4);
Form1.Listbox1.Items.Add(Linia);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
EnumWindows(@EnumWindowsProc,0);
end;
Na formie powinien być komponent typu TListBox. Zostanie on wypełniony listą
aktywnych okien.
Źródło informacji: Sławomir
Świder
24. Dlaczego program korzystający z baz
danych po przeniesieniu na inny komputer nie chce działać?
bazy danych, BDE, błąd
Delphi korzysta z BDE (Borland Database Engine). Jest to program
pośredniczący pomiędzy Delphi a bazami danych i musi być zainstalowany na
docelowym komputerze. Można to zrobić "ręcznie" - na kompakcie z Delphi jest
katalog z wersją instalacyjną samego BDE. Można też użyć InstallShield Express -
jest to okrojona wersja programu do tworzenia programów instalacyjnych. Znajduje
się na płycie z Delphi. Jedną z jego opcji jest właśnie instalowanie programów
wymagających BDE. Jest szybki i robi to całkiem nieźle.
Najczęstszym objawem braku BDE jest błąd nr 2109 z komunikatem "brak pliku
IDAPI32.DLL".
25. Jak reagować na zmianę
rozdzielczości w trakcie działania programu?
rozdzielczość, ekran, zmiana
Należy obsłużyć komunikat wm_DisplayChange dopisując do formy
procedurę:
procedure WMDisplayChange(var msg :
TWMDisplayChange);message wm_DisplayChange;
Dodatkowo w Delphi 2.0 trzeba dopisać definicję typu:
type
TWMDisplayChange = record
Msg: Cardinal;
BitsPerPixel: Integer;// ilość
kolorów - 8-256, 15-32k, 16-64k,24/32-16mln
Width: Word; //szerokość
Height: Word; //wysokość
end;
Należy ją umieścić przed deklaracją procedury. Aby przeczytać o dodawaniu
własnej obsługi komunikatów zajrzyj do pytania 16.
Uwaga: Komunikat wm_DisplayChange jest specyficzny dla Windows 95 nie
występuje ani w Windows NT ani w Win32s API. Wczesne wersje Windows 95 mogą
wysyłać ten komunikat dwukrotnie - przed i po zmianie rozdzielczości.
Źródło informacji: Krzysztof
Świątkowski.
26. Jak dodać wizytówkę programu (ang.
splash screen)?
wizytówka, logo, splash,
ładowanie
Należy stworzyć nową formę, nazwać ją np. TLogo, ustawić właściwości
| BorderStyle |
bsNone |
| BorderIcons |
[] |
| FormStyle |
fsStayOnTop |
Do formy dodać TImage z obrazkiem. Tak przygotowaną formę należy jeszcze
usunąć z listy automatycznie tworzonych form (jak to zrobić patrz pytanie 10).
Teraz przechodzimy do kodu źródłowego projektu.
begin
Application.Initialize;
// Utworzenie i pokazanie formy
Logo:=TLogo.Create(Application);
Logo.Show;
Logo.Update;
// Tu wstawia Delphi utworzenie automatycznych form
Application.Run;
end;
Do okna głównego dodajemy:
procedure TForm1.FormShow(Sender :
TObject);
begin
if assigned(Logo) then
begin
Logo.Free;
Logo:=nil;
end;
end;
I gotowe. W katalogu DEMOS na płycie z Delphi znajduje się program MASTAPP z
winietą.
27. Jak dodać właściwości do formy aby
były widoczne w okienku ObjectInspector?
właściwości, ObjectInspector, dziedziczenie, forma
Dokładnej odpowiedzi nie znam. Przytoczę tu fragment listu Roberta Perlińskiego:
"Niestety nie mogę odnaleźć kawałka kodu, który napisałem jakiś czas temu, a
który implementował dokładnie to o czym mówimy. Z głowy i z tego co
pamiętam:
1. Tworzymy moduł z definicją formy np. TPawelForm, która zawiera "custom
property" np. PawelProperty. Forma powinna przeciążać konstruktor Create, ale
zamiast standardowego inherited powinna wołać CreateNew i InitInheritedComponent
(patrz TCustomForm.Create zdefiniowane w pliku forms.pas)
2. Tworzymy "Module Creator" np. TPawelFormCreator =
class(TIModuleCreator)
3. Tworzymy "Expert" np. TPawelFormExpert = class(TIExpert)
4. Rejestrujemy TPawelForm i TPawelFormExpert
5. Jeśli w p. 1-4 zrobiliśmy wszystko jak należy, każda nowa forma utworzona
przy pomocy TPawelFormExpert, posiadać powinna PawelPropety dostępną z poziomu
Object Inspectora. Obiecuję, że jeśli odnajdę pełny tekst programu, wyślę go na
listę."
I tyle Robert. Niestety programu chyba nie wysłał (przynajmniej ja go nie
zauważyłem).
Źródło informacji: Robert
Perliński
28. Jak pobrać listę właściwości obiektu
w trakcie wykonywania programu?
właściwości, RTTI,
runtime
Poniżej jest tłumaczenie Delphi TI 3166:
Czasem przydatna jest informacja o właściwościach komponentu w momencie
wykonywania programu. Listę właściwości można uzyskać przy pomocy funkcji
GetPropList. Typy, funkcje i procedury (włączając w to
GetPropList) pozwalające na dostęp do właściwości znajdują się w pliku
TYPINFO.PAS.
GetPropList jest zdefiniowana jako:
function
GetPropList(TypeInfo: PTypeInfo; TypeKinds: TTypeKinds;
PropList: PPropList): Integer;
Pierwszym parametrem GetPropList jest zmienna typu PTypeInfo,
jest to część RTTI (Run Time Type Information) dostępnej dla każdego obiektu.
Typ ten jest zdefiniowany następująco:
PPTypeInfo =
^PTypeInfo;
PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;
Rekord TTypeInfo może być odczytany przy pomocy właściwości
ClassInfo obiektu. Na przykład, jeśli pobieramy informacje o
TButton wywołanie może wyglądać następująco:
GetPropList(Button1.ClassInfo, ....
Drugi parametr (typu TTypeKinds) jest typu zbiorowego i działa jak
filtr decydując o tym jakie rodzaje właściwości zamieścić w liście. Jest kilka
możliwych wartości jakie można mu nadać jednakże tkProperties obsługuje
najważniejsze. Teraz wywołanie ma postać:
GetPropList(Button1.ClassInfo, tkProperties ....
Ostatni parametr, PPropList jest tablicą typów PPropInfo:
PPropList
= ^TPropList;
TPropList = array[0..16379] of PPropInfo;
Teraz nasze wywołanie może mieć postać:
procedure
TForm1.FormCreate(Sender: TObject);
var PropList: PPropList;
begin
PropList := AllocMem(SizeOf(PropList^));
GetPropList(TButton.ClassInfo, tkProperties + [tkMethod],
PropList);
...
Przykład przytoczony poniżej pokazuje nie tylko nazwę właściwości ale także
jej typ. Nazwa typu znajduje się w dodatkowej strukturze w rekordzie
TPropInfo. Zauważmy, że pole PropType wskazuje na rekord
TTypeInfo zawierający nazwę typu właściwości:
PPropInfo =
^TPropInfo;
TPropInfo = packed record
PropType: PPTypeInfo;
GetProc:
Pointer;
SetProc:
Pointer;
StoredProc: Pointer;
Index: Integer;
Default: Longint;
NameIndex: SmallInt;
Name: ShortString;
end;
PPTypeInfo = ^PTypeInfo;
PTypeInfo = ^TTypeInfo;
TTypeInfo = record
Kind: TTypeKind;
Name: ShortString;
{TypeData: TTypeData}
end;
Poniższy kod przykładowy pokazuje jak wywołać GetPropList i jak
odwoływać się do elementów zwróconej tablicy. Przykład wymaga obecności na
formie TListBox:
uses TypInfo;
procedure TMainForm.FormCreate(Sender: TObject);
var PropList: PPropList;
i: integer;
begin
PropList:=AllocMem(SizeOf(PropList^));
i:=0;
try
GetPropList(TForm.ClassInfo,tkProperties+[tkMethod],PropList);
while (PropList^[i]<>Nil)and(i<High(PropList^)) do
begin
ListBox1.Items.Add(PropList^[i].Name+':'+PropList^[i].PropType^.Name);
Inc(i);
end;
finally
FreeMem(PropList);
end;
end;
Tyle Borland. Ze swej strony dodam, że aby powyższe działało obiekt musi być
kompilowany z włączeniem generowania RTTI lub być pochodną takiego obiektu. RTTI
jest włączone dla jednego obiektu z VCL - TPersistent. Wystarczy więc, że
nasz obiekt będzie pochodną TPersistent. To dla tych, którzy nie mają
dostępu do źródeł bibliotek. Dla pozostałych informacja jak włączyć generowanie
RTTI. Proszę spojrzeć na deklarację TPersistent:
{ TPersistent abstract class
}
{$M+}
TPersistent = class(TObject)
private
procedure AssignError(Source: TPersistent);
protected
procedure AssignTo(Dest: TPersistent); virtual;
procedure DefineProperties(Filer: TFiler); virtual;
function GetOwner: TPersistent; dynamic;
public
destructor Destroy; override;
procedure Assign(Source: TPersistent); virtual;
function GetNamePath: string; dynamic;
end;
{$M-}
Widać, że za RTTI jest odpowiedzialny przełącznik {$M+} (można go
zapisać też jako {$TYPEINFO ON}). Polecam odpowiednią stronę w helpie.
Jest tam między innymi napisane, że RTTI jest generowane tylko dla pól w części
published (nad czym niezmiernie boleję).
Źródło informacji: Delphi TI
3166
29. Jak dodać własną pozycję do menu
wywoływanego spod Exploratora po kliknięciu prawym przyciskiem
myszy?
Explorer, Explorator, menu podręczne, prawy
przycisk myszy
Odpowiedź podał Michał
Jaskólski:
procedure JakasTam;
var
Rejestr:TRegistry;
NazwaTypu:string;
begin
try
Rejestr:=TRegistry.Create;
Rejestr.RootKey := HKEY_CLASSES_ROOT;
Rejestr.OpenKey('\.rozszerzenie',true);
NazwaTypu:=Reg.ReadString('');
Rejestr.CloseKey;
Rejestr.OpenKey('\'+NazwaTypuHtml+'\shell\Koduj',true);
Rejestr.WriteString('','Koduj do...');
Rejestr.CloseKey;
Rejestr.OpenKey('\'+NazwaTypuHtml+'\shell\Koduj\command',true);
Rejestr.WriteString('','"'+Application.ExeName+'"
"%1"');
Rejestr.CloseKey;
finally
Rejestr.Free;
end;
end;
Źródło informacji: Michał
Jaskólski
30. Jak sprawdzić czy uruchomiony
program jest już w pamięci?
powtórne uruchamianie,
dwa programy
Odpowiedź podał Paweł
Schmidt:
hMapping:=CreateFileMapping(THANDLE($FFFFFFFF),nil,
PAGE_READONLY,0,32,'ApplicationTestMap');
if GetLastError=ERROR_ALREADY_EXISTS then
begin
Application.MessageBox('Program jest już
uruchomiony','Informacja',
mb_OK+MB_IconInformation);
Application.Terminate;
end;
Od siebie dodam, że przy końcu aplikacji warto zrobić CloseHandle(hMapping).
W Delphi 1.0 wystarczy sprawdzić wartość parametru HPrevInstance, jeśli jest
niezerowy to program został już uruchomiony.
31. Jak wyświetlić standardowe okno
Windows służące do wybierania katalogu?
katalog,
standardowe okno, dialog, wybór
Należy skorzystać z funkcji SHBrowseForFolder:
uses
ShlObj,ActiveX;
procedure TForm1.Button1Click(Sender: TObject);
var BI:TBrowseInfo;
Buf:PChar;
Dir,Root:PItemIDList;
Alloc:IMalloc;
begin
// Pobieramy obiekt zarządzający pamięcią
SHGetMalloc(Alloc);
// Przydzielamy pamięć na string
Buf:=Alloc.Alloc(Max_Path);
// Ograniczamy wybór tylko do katalogu "Menu Start\Programs"
SHGetSpecialFolderLocation(Handle,CSIDL_PROGRAMS,Root);
with BI do
begin
hwndOwner:=Form1.Handle;
pidlRoot:=Root; // Tu można podać NIL żeby można
było wybrać każdy katalog
pszDisplayName:=Buf;
lpszTitle:='Wybierz katalog'; // Etykietka przed listą
katalogów
ulFlags:=0;
lpfn:=nil;
end;
try
Dir:=SHBrowseForFolder(BI);
if Dir<>Nil then
begin
// Pobieramy pełną ścieżkę do katalogu
SHGetPathFromIDList(Dir,Buf);
// Przykładowe zastosowanie
ShowMessage(Buf);
Alloc.Free(Dir);
end;
finally
Alloc.Free(Root);
Alloc.Free(Buf);
end;
end;
Inne możliwe do wybrania katalogi specjalne:
| CSIDL_BITBUCKET |
RecycleBin czyli kosz na śmieci |
| CSIDL_CONTROLS |
Wirtualny katalog ControlPanel |
| CSIDL_DESKTOP |
Wirtualny katalog Desktop |
| CSIDL_DESKTOPDIRECTORY |
Katalog na dysku przechowujący obiekty z desktopu |
| CSIDL_DRIVES |
My Computer |
| CSIDL_FONTS |
Wirtualny folder z fontami |
| CSIDL_NETHOOD |
Otoczenia sieciowe |
| CSIDL_NETWORK |
Wirtualny odpowiednik powyższego |
| CSIDL_PERSONAL |
Katalog Personal |
| CSIDL_PRINTERS |
Wirtualny folder z drukarkami |
| CSIDL_PROGRAMS |
Programy z menu Start |
| CSIDL_RECENT |
Ostatnio użyte dokumenty |
| CSIDL_SENDTO |
Folder SendTo |
| CSIDL_STARTMENU |
Całe StartMenu |
| CSIDL_STARTUP |
Grupa Autostart |
| CSIDL_TEMPLATES |
Szablony dokumentów |
Wartości CSIDL_PROGRAMS można użyć przy dodawaniu własnych pozycji w menu
Start.
32. Czy jest możliwe skompilowanie
programu napisanego w Delphi 3.0 tak aby działał w Windows 3.11?
Windows 3.11, thunk, Win32s, 16-bit
Nie próbowałem tego w Delphi 3.0 ale kompilowałem kilka programów pod Delphi
2.0 korzystających z wielu komponentów Delphi (ale nie korzystałem bezpośrednio
z WinAPI) i nie było żadnych problemów z uruchomieniem ich pod Windows 3.11.
Oczywiście w docelowym systemie musi być zainstalowana nakładka Win32s. Jeśli
chcesz korzystać bezpośrednio z WinAPI to sprawdź czy funkcja, której używasz ma
swój odpowiednik w Win32s API. Pod Delphi 3.0 nie powinno być żadnych problemów
pod warunkiem, że nie korzystamy z obiektów z zakładki Win32. Dodam jeszcze, że
moje programy nie korzystały z baz danych (co nie znaczy, że takowe nie
będą działać, po prostu testy musisz przeprowadzić we własnym zakresie).
33. Gdzie i za ile można kupić Delphi,
gdzie można znaleźć informację o tym produkcie?
Delphi, kupno, BSC
Dystrybutorem produktów Borlanda w Polsce jest Borland Support Center. Tam też znajdują się
aktualne ceny. Informacje można znaleźć na wspomnianym BSC jak również na
stronach Inprise (dawniej Borland).
Niektórzy twierdzą, iż taniej jest sprowadzić Delphi ze Stanów niż kupować w
Polsce.
34. Jak dodać do formy w czasie
wykonywania programu kilka komponentów?
forma,
komponenty, dodawanie
Należy dokładnie powtórzyć to co robi Delphi przy dodawaniu komponentów:
- utworzyć komponent przy pomocy TEdit.Create(Form1)
- ustawić właściwość parent na komponent nadrzędny (najczęściej formę ale
czasem będzie to na przykład panel) wykonując Edit.Parent:=Form1
- Poustawiać resztę interesujących nas właściwości
procedure
TForm1.Button1Click(Sender: TObject);
var I,Y:Integer;
Edit:TEdit;
begin
Y:=5; // Pozycja, od której zaczynamy dodawać
obiekty
for I:=1 to 5 do
begin
Edit:=TEdit.Create(Self);
Edit.Parent:=Self;
// Tyle wystarczy aby poprawnie dodać obiekt
// Poniżej ustawiamy te właściwości, które chcemy
Edit.Top:=Y;
Edit.Left:=5;
Edit.Text:=Format('Okienko nr %d',[I]);
// Następne okno utworzymy poniżej z odstępem 2 pikseli
Y:=Y+Edit.Height+2;
end;
end;
Nie musimy martwić się o zniszczenie obiektów destruktorem. Są one
automatycznie zwalniane przez formę.
35. Jak wydrukować zawartość
memo?
TMemo, drukowanie
Należy skorzystać z modułu Printers i procedury AssignPrn.
procedure
TForm1.Button1Click(Sender: TObject);
var I:Integer;
F:TextFile;
begin
AssignPrn(F);Rewrite(F);
try
// Wypisujemy nagłówek kursywą...
Printer.Canvas.Font.Style:=[fsBold];
Writeln(F,'Zawartość memo');Writeln;
// ... i zawartość memo linia po linii
Printer.Canvas.Font.Style:=[];
for I:=0 to Memo1.Lines.Count-1 do
Writeln(F,Memo1.Lines[I]);
finally
CloseFile(F);
end;
end;
Plik zaraz po wydruku musimy zamknąć gdyż tylko jeden plik może być
skojarzony z drukarką. Należy też dodać w sekcji Uses moduł
Printers bo stamtąd pochodzi procedura AssignPrn.
36. Jak obsłużyć COM spod Delphi
2.0?
COM, port szeregowy, transmisja
Oto przykładowy kod nadesłany przez MARFI:
procedure
TForm.Button1Click(Sender : TObject);
var hCOM:THandle;
nrWrit:DWORD;
nrRead:DWORD;
Errors:DWORD;
Dcb:TDCB;
ComStat:TComStat;
buf:array[0..2048] of char;
begin
//Otwarcie łącza COM
hCOM:=CreateFile('COM3',GENERIC_WRITE OR GENERIC_READ,0,nil,OPEN_EXISTING,0,0);
//Ustawienie parametrów transmisji - jak MODE w DOS'ie
if hCOM<>INVALID_HANDLE_VALUE then
begin
GetCommState(hCOM,Dcb);
BuildCommDCB('19200,n,8,2',Dcb);
SetCommState(hCOM,Dcb);
end
else
begin
ShowMessage('Błąd otwarcia portu COM :
'+IntToStr(GetLastError()));
Exit;
end;
try
//Przygotowanie bufora
ZeroMemory(@buf,SizeOf(buf));
StrCopy(buf,'AT&V'+#13+#10);
//Zapis bufora
if not WriteFile(hCOM,buf,StrLen(buf),nrwrit,nil) then
ShowMessage('Błąd zapisu do portu COM.');
//Sprawdzenie czy jest coś w buforze COM
ClearCommError(hCOM,Errors,@ComStat);
//Odczytanie bufora gdy są dane
if ComStat.cbInQue>0 then
ReadFile(hCOM,buf,ComStat.cbInQue,nrRead,nil);
finally
CloseHandle(hCOM);
end;
end;
Źródło informacji: MARFI
37. Co to jest RxLib i skąd to można
ściągnąć?
RxLib, RxHint
RxLib jest biblioteką komponentów do Delphi 1, 2 i 3 w postaci kodów
źródłowych. Jej autorami są Rosjanie a ściągnąć ją można z DSP lub bezpośrednio od autorów.
38. Jak dodać nową wartość klucza do
rejestru?
rejestr, klucz
Należy skorzystać z obiektu TRegistry. Przykład:
procedure
TMainForm.Button1Click(Sender: TObject);
var Reg:TRegistry;
begin
Reg:=TRegistry.Create;
try
Reg.RootKey:=HKEY_LOCAL_MACHINE;
Reg.OpenKey('Firma',True);
Reg.WriteString('Sciezka','c:\Program Files\Firma');
Reg.WriteInteger('Wersja',1);
finally
Reg.Free;
end;
end;
39. Jak zamienić liczbę na "słownie
złotych"?
słownie, kwota
Tu możesz ściągnąć przykładowy moduł.
40. Jak wyrażenie matematyczne zamienić
na liczbę?
obliczanie, VAL$, funkcje,
kalkulator
Tu możesz ściągnąć przykładowy moduł do
Turbo Pascala. Aby użyć go z Delphi trzeba go trochę przerobić bo w Delphi
zmienił się sposób obsługi obiektów.
41. Jak odczytać numer seryjny dysku lub
dyskietki?
numer seryjny, dysk, dyskietka,
CD-ROM
Dla dysku metoda jest nieznana :-((dokładniej - działa poniższy kod ale nie
daje numeru dysku tylko numer seryjny partycji) Dla dyskietki powinna działać
poniższa procedura:
var
Buf:array[0..MAX_PATH] of Char;
NotUsed,VolFlags:Integer;
DriveChar:Char;
Serial:PDWORD;
begin
DriveChar := 'a';
GetVolumeInformation(PChar(DriveChar +
':\'),Buf,sizeof(Buf),
@Serial,NotUsed,VolFlags,nil,0);
end;
W zmiennej Serial jest numer dyskietki.
Źródło informacji: Artur
Bajor
42. Czy w Delphi istnieje odpowiednik
komend IN, OUT umożliwiających wysłanie pod określony adres urządzenia WE-WY
określonej liczby?
Port, IN, OUT, porty
Zacytuję Artura Bajora:
"Nie istnieje.(...) Pisanie i odczyt portów można realizować przez wstawkę
asm:
function PortIn(Port:word):Byte;
var Help:Byte;
begin
asm
mov DX ,Port
in AL ,DX
mov Help ,AL
end;
PortIn:=Help;
end;
procedure PortOut(Port:word;Value:Byte);assembler;
asm
mov DX,Port
mov AL,Value
out DX,AL
end;
"Podkreślam (co już było dyskutowane na tej liście), że Win95 skutecznie
zabroni Ci dostępu do niektórych portów we/wy (np. HDD Controller) , co jest
całkiem naturalne nawet w tak stabilnym systemie jak winda ;-) Jeżeli jednak są
to porty np. Twojej karty, z powodzeniem będziesz mógł pisać i czytać we/wy, bo
to samo robiłem w swojej."
Źródło informacji: Artur
Bajor
43. Napisałem program korzystający z
THTML i po przeniesieniu na inny komputer pojawia się błąd "Exception
EOleSysError in module..." co się dzieje?
EOleSysError, OCX, HTML
Komponent THTML trzeba zarejestrować gdyż jest to kontrolka OCX. Można zrobić
to używając programu regsrv32.exe lub ręcznie na początku programu. Większy
problem to to, że ta kontrolka składa się z kilku plików i wszystkie trzeba
przenieść do komputera docelowego do katalogu Windows\System lub katalogu z
Twoim programem. Jakie pliki przenieść można sprawdzić w dokumentacji kontrolki
lub sprawdzając w QuickView jakich bibliotek używa (poza standardowymi z
Windows). Metodą czołgową można również kopiować po jednym pliku gdyż komunikaty
o błędach podają czasem, którego pliku brakuje. Poniżej podaję procedury do
rejestracji kontrolek OCX:
function CheckOCX:Boolean;
var Reg:TRegistry;
begin
Reg:=TRegistry.Create;
try
Reg.RootKey:=HKEY_CLASSES_ROOT;
// Poniżej jest UID kontrolki wyciągnięty z rejestru Windows
Result:=Reg.OpenKey('CLSID\{B7FC3550-8CE7-11CF-9754-00AA00C00908}',False);
if Result then Reg.CloseKey;
finally
Reg.Free;
end;
end;
procedure RegisterOCX;
var Lib:THandle;
S:String;
P:TProcedure;
begin
OleInitialize(nil);
try
S:=ExtractFilePath(Application.ExeName)+'HTML.OCX';
Lib:=LoadLibrary(PChar(S));
if Lib<HINSTANCE_ERROR then
raise Exception.CreateFmt('Cannot initialize library %s. '+
'Internal Windows error %d',[S,Lib]);
try
P:=GetProcAddress(Lib,'DllRegisterServer');
if not Assigned(P) then raise
Exception.Create('Cannot find '+
'procedure DllRegisterServer');
P;
finally
FreeLibrary(Lib);
end;
finally
OleUninitialize;
end;
end;
procedure Uninstall;
var Lib:THandle;
S:String;
P:TProcedure;
begin
S:=ExtractFilePath(Application.ExeName)+'HTML.OCX';
Lib:=LoadLibrary(PChar(S));
if Lib<HINSTANCE_ERROR then
raise Exception.CreateFmt('Cannot initialize library %s.'+
' Internal Windows error
%d',[S,Lib]);
try
P:=GetProcAddress(Lib,'DllUnregisterServer');
if not Assigned(P) then raise
Exception.Create('Cannot find procedure '+
'DllUnregisterServer');
P;
finally
FreeLibrary(Lib);
end;
end;
Powinno się udostępnić opcję wymuszenia instalacji komponentu. Miałem problem
gdy komponent był zarejestrowany ale nie było go na dysku.Wtedy pojawiał się
błąd. Dzieje się tak najczęściej na komputerach, na których ktoś wcześniej
instalował Delphi. Możliwe, że uninstall z Delphi nie usuwa wpisów w rejestrze a
usuwa pliki. Aby powyższe działało można:
- wrzucić wszystkie pliki kontrolki do katalogu z programem
- na początku projektu sprawdzać czy kontrolka jest zarejestrowana
- jeśli nie jest to ją zarejestrować
- jeśli jest to zapamiętać, że jest
- na końcu programu (przy wyjściu) odrejestrować kontrolkę ale tylko wtedy
gdy nie była zarejestrowana przed wywołaniem programu
- jeśli ktoś użyje parametru przy uruchomieniu programu to traktować ten
przypadek jako brak instalacji kontrolki
Można też sprawdzanie instalacji zamienić na próbne utworzenie kontrolki.
Jeśli Delphi rzuci wyjątek EOleSysError to znaczy, że trzeba ją
zainstalować. IMHO OCX-y są trochę niewygodne. Wolę komponenty "100% pure
Delphi". Przykładowe procedury były pisane do komponentu THTML. Aby rejestrować
inne komponenty trzeba znać ich GUID i nazwę pliku, w którym się znajdują.
Informacje te można wziąć z dokumentacji lub rejestru Windows.
44. Jak wywołać program 32-bitowy i
poczekać na jego zakończenie?
wywołanie,
32-bit
Można skorzystać z poniższego przykładu:
procedure
TForm1.Button1Click(Sender: TObject);
var SI:TStartupInfo;
PI:TProcessInformation;
S,Dir:String;
begin
Dir:=ExtractFilePath(Application.ExeName);
S:='winrar95.exe a '+Dir+'test.rar '+Dir+'*.*';
FillChar(SI,sizeof(SI),0);
with SI do
begin
dwFlags:=STARTF_USESHOWWINDOW;
wShowWindow:=SW_SHOW;
cb:=sizeof(TStartupInfo);
end;
if CreateProcess(nil,PChar(S),nil,nil,FALSE,NORMAL_PRIORITY_CLASS,nil,nil,SI,PI) then
with PI do
begin
WaitForInputIdle(hProcess,1000);
WaitForSingleObject(hProcess,10000);
WaitForSingleObject(hThread,10000);
CloseHandle(hProcess);
CloseHandle(hThread);
end;
end;
Oczywiście trzeba zmienić wartości przekazywane w zmiennej S ale idea
pozostaje ta sama.
Źródło informacji: Marian Ficek
45. Jak wyświetlić plik JPG (instalacja
jpeg.dcu z katalogu LIB nie pomaga)?
JPEG, JPG,
LIB
Oto co proponuje Grzegorz Meus:
"Koniecznie wpisz w sekcji USES twojego modułu nazwę JPEG.
Wtedy gdy wrzucisz na swój formularz np. komponent OpenPictureDialog
(sekcja Dialogs z Delphi 3) będziesz miał dostęp do plików graficznych
typu .JPG i od razu także ich podgląd w okienku tego dialogu. Aby samodzielnie
taki obrazek wyświetlać dodatkowo wrzuć jakiś PaintBox na formularz,
następnie zadeklaruj zmienną typu TPicture do przechowywania obrazu JPEG
w pamięci
TForm1 = class(TForm)
...
OpenPictureDialog1: TOpenPictureDialog;
...
private
{ Private declarations }
FPicture : TPicture;
...
end;
Nie zapomnij o utworzeniu zmiennej FPicture zadeklarowanej wyżej (np.
w TForm1.FormCreate):
FPicture := TPicture.Create;
oraz oczywiście jej zniszczeniu (np. w TForm1.FormDestroy)
FPicture.Free;
No i teraz w programie, zakładając że masz ścieżkę do pliku typu JPG w
zmiennej FName : String, robisz coś takiego:
try
FPicture.LoadFromFile(FName);
except
on EInvalidGraphic do
begin
MessageDlg('Invalid graphic file:
'+FName,mtError,[mbOk],0);
Exit;
end;
end;
PaintBox1.Invalidate;
a w procedurce TForm1.PaintBox1Paint:
with PaintBox1 do
begin
DrawRect:=Rect(0,0,Width,Height); //ramka wokół ...
//i
Canvas.Draw(Left+(Right-Left-FPicture.Width)div 2,
Top+(Bottom-Top-FPicture.Height)div
2,FPicture.Graphic);
//lub
Canvas.StretchDraw(DrawRect,FPicture.Graphic);
end;
Powodzenia !"
Źródło informacji: Grzegorz Meus
46. Jak zrobić wygaszacz w Delphi
1.0?
wygaszacz
Oto co proponuje Tomasz
Witek:
"...napisałem kiedyś taki wygaszacz. Bardzo prosto. Forma bez ramek, bez
linijki, maximized, czuła na myszkę, zawierająca description w postaci:
{$D
SCRNSAVE:Wygaszacz}
{Tylko jedna kopia programu może być uruchomiona}
if hPrevInst = 0 then
begin
if (ParamCount > 0) and (UpperCase(ParamStr(1)) =
'/S')
begin
{ Setup wygaszacza }
end
else
begin
{ Wygaszacz }
end;
Sam wygaszacz powinien uruchamiać się tylko po /C ale nie musi :)))
To by
było wszystko."
Źródło informacji: Tomasz
Witek
47. Jak dodać skrót do Desktopu lub Menu
Start w Windows 95?
skrót, pasek Start, menu,
desktop, ikona
Poniższe pochodzi z Delphi TI 3234:
Poniższy przykład pokazuje jak dodać skróty na desktop i menu Start w Windows
95 i Windows NT 4.0. Skrót zostanie dodany w jednym z tych miejsc (patrz kod).
Położenie desktopu i menu Start pobierane jest z rejestru (z gałęzi
HKEY_CURRENT_USER):
Software\MicroSoft\Windows\CurrentVersion\Explorer\Shell Folders
uses
ShlObj, ActiveX, ComObj, Registry;
procedure TForm1.Button1Click(Sender: TObject);
var MyObject:IUnknown;
MySLink:IShellLink;
MyPFile:IPersistFile;
FileName:String;
Directory:String;
WFileName:WideString;
MyReg:TRegIniFile;
begin
MyObject:=CreateComObject(CLSID_ShellLink);
MySLink:=MyObject as IShellLink;
MyPFile:=MyObject as IPersistFile;
FileName:='NOTEPAD.EXE';
with MySLink do
begin
SetArguments('C:\AUTOEXEC.BAT');
SetPath(PChar(FileName));
SetWorkingDirectory(PChar(ExtractFilePath(FileName)));
end;
MyReg :=
TRegIniFile.Create('Software\MicroSoft\Windows\CurrentVersion\Explorer');
// Poniższe dodaje skrót do desktopu
Directory := MyReg.ReadString('Shell
Folders','Desktop','');
// A to do menu Start
// Directory := MyReg.ReadString('Shell Folders','Start Menu','')+
// '\Whoa!';// CreateDir(Directory);
WFileName := Directory+'\FooBar.lnk';
MyPFile.Save(PWChar(WFileName),False);
MyReg.Free;
end;
Źródło informacji: Delphi TI
3234.
48. Mam problemy z bazami danych w
sieci, nie pojawiają się zmiany w bazach.
sieć, BDE,
bazy danych, Paradox
Oto co na ten temat pisze Krzysztof
Szyszka
"Ponieważ już parę razy odpowiadałem na pytania dotyczące różnych problemów
związanych z pracą w sieci na bazach dBase i Paradox, a pytania ciągle się
pojawiają, więc pokuszę się o krótkie zebranie zaleceń wynikających z moich
własnych doświadczeń. (...)
- Ustawić w BDE Administratorze parametr Configuration/System/INIT/LOCAL
SHARE na True na wszystkich stacjach, jeśli korzystamy z sieci typu
peer-to-peer np. Microsoft Network.
- Dla baz Paradoxa ustawić Configuration/Drivers/Native/PARADOX/NET DIR lub
Session.NetFileDir na ten sam fizycznie plik PDOXUSRS.NET. Niektórzy zalecają
umieścić ten plik w katalogu baz danych.
- Ustawić Session.PrivateDir na roboczy katalog lokalnego dysku, chyba że
mamy pewność, że bieżącym katalogiem przy starcie programu będzie katalog na
lokalnym dysku.
- Zostawić domyślne ustawienie Table.CachedUpdates na False. Przy ustawieniu
na True należy być świadomym, że wszystkie operacje na bazie wykonywane są
jedynie w pamięci bez zapisu na dysk, a więc i bez wykonywania funkcji
sieciowych.
- W zdarzeniu AfterPost każdej tabeli danych wymusić zapis buforów BDE na
dysk poleceniem: Check(dbiSaveChanges(Table.Handle)). Dla tabel służących do
przetwarzania większej porcji rekordów można wykonać to po zakończeniu
aktualizacji, jeśli nie dokonujemy zmian w polach kluczowych dla pracy w
sieci. Z punktu widzenia bezpieczeństwa danych lepiej wykonywać to po każdym
Post, kosztem szybkości przetwarzania rekordów.
- Po wykonaniu każdego polecenia dostępnego użytkownikowi, które operuje na
bazach danych, należy wykonać Table.Refresh dla uwidocznienie zmian dokonanych
ostatnio w bazie przez innych użytkowników. Ma to szczególne znaczenie wtedy,
gdy polecenie zakończy się komunikatem o błędzie np. 'Record locked by another
user.', 'No current record.', 'Rekord/Key deleted.', itp.
- Dla tabel podłączonych do komponentów, które operują jednocześnie na
więcej niż jednym rekordzie danych (np. DBGrid) wykonać dodatkowo
DBGrid.Refresh, dla uwidocznienie zmian w pozostałych wierszach danych. W
programach które prezentują jednocześnie kilka okien danych warto podłączyć
Table.Refresh (i DBGrid.Refresh) pod zdarzenie OnActivate, żeby uczynienie
okna aktywnym, wiązało się zawsze z odświeżeniem danych.
- Wykonując instalacje programu wymagającego BDE przy pomocy InstallShielda
można dopisać własne Aliasy, ale nie można spowodować zmian w parametrach z
zakładki Configuration (w każdym razie mnie się to nie udało), dlatego warto
zmodyfikować ręcznie plik \InstallShield\redist\IDAPI32.CNF, dokonując np.
zmiany domyślnego ustawienia dla LOCAL SHARE na True."
Źródło informacji: Krzysztof
Szyszka
49. Jak przeszukiwać Delphi Help i Win32
Help jednocześnie?
help, pomoc,
przeszukiwanie
Należy dopisać poniższy tekst do Delphi3.CNT:
:Index Win32=win32.hlp
wtedy w indeksie jest zarówno Delphi jak i WinAPI.
Źródło informacji: Krzysztof
Świątkowski
50. Gdzie mogę znaleźć dodatkowe
informacje o Delphi?
linki
Poniżej jest kilka linków zebranych i opracowanych przez Tomasza Kustrę i Radosława "Radio Erewan" Przybyła:
I. Komponenty
Delphi Super Page
Torry's Delphi Page
Delphi Free Stuff
Radek Delphi Page
Animated Menus98
Artem's Delphi
Stuff
CoolForm ("okrągłe
okienka")
RX Library
(lepiej ściągać z mirrora w Polsce)
Latające toolbary Jordana
Russela
Delphi Games
Creator
Une Page Delphi
2+
Delphi
Companion
Programers
Heaven
JG's Home Page
American Freehold C++Builder/Delphi
Freeware
Delphi3.com
InfoTrade Virtual Code
Library
http://www.balticsolutions.com/
http://www.htmlreport.com/
II. Wiedza/Żródła
Archiwum
pl.comp.lang.delphi
Delphi Companion
Delphi Sites
The Unoficial Newsletter of Delphi Users
Dr Bob`s Delphi Clinic
Programers Heaven
The Delphi EXchange
Delphi3.com
eMEDES Software :
Delphi Source Code
Ask the Delphi
Pro
FreeCode
Delphi Developer on line
Zagozda Software -
Delphi w przykładach
WinAPI-FAQ
III. Borland/Inprise:
Strona główna
Delphi Developer's
Jurnal
Delphi
Developer Support
Common Delphi Question
and Answers
BSC (Borlsnd Support Center)
- polski reprezentant Inprise
IV. Inne źródła:
MSDN Technologies
Win32 Development
COM Technologies
SWAG (Sourceware Archive Group)
(np.formaty większości plików graficznych)
V. Linki
Delphi Sites
Programers Heaven
ITM - Delphi Search
Engine
Delphi
Developers
Delphi3.com
Turbo Pascal Programers
Page
Źródło informacji: Tomasz
Kustra, Radosław "Radio Erewan"
Przybył, Piotr Neil "Gawron"
Gawronski