Display digital

Display digital

Postby DarkByte » 20 Feb 2011, 17:40

Mai tineti minte calculatoarele de buzunar si ceasurile de mana digitale ? In perioada 1985-1995 erau la mare cautare printre copii - eu, cel putin, eram mort dupa ele :D ... afisajul lor digital imi placea foarte mult. Daca era ceas cu calculator incorporat, erai deja "cool" :)) ... Era ceva diferit decat lucrurile uzuale care se puteau gasi pe atunci. Acum gasesti afisaje digitale si la ceasuri desteptatoare, la cuptoarele cu microunde, etc.

Am tot vazut, de-a lungul timpului, chiar si programe pe calculator care foloseau afisaje digitale - nu ca ar fi neaparat necesar. Oricum, m-am decis (aseara, dar nu m-am urnit pana azi :P) sa fac o replica a acelor afisaje digitale in Delphi.

Sa vedem, totusi, cum desenam cifrele. M-am gandit sa encodez fiecare piesa posibila pe cate un bit, ca in "diagrama" urmatoare:
Image
Dupa cum se observa, daca tot mi-a ramas un bit, am adaugat si semnul de doua puncte (" : ") pe ultima pozitie - 7.

Folosind diagrama si convertind din binar in zecimal, se gasesc, rapid, valorile care se vor hard-coda in program - formele cifrelor - intr-un array care foloseste ca indecsi chiar caracterele cifrelor (ASCII). Dupa cum se poate calcula (si observa in programul de mai jos), caracterul "3" are valoarea 109 - care, in binar, salveaza forma cifrei 3. Easy as that !

In functie de bit si pozitionarea piesei corespunzatoare, desenatul unei cifre este floare la ureche. Eu am decis ca piesele care nu fac parte din caracter sa fie totusi afisate cu un gri inchis - tot in amintirea zilelor in care afisajurile digitale erau, oarecum, o noutate.

Codul, in toata splendoarea lui, este urmatorul:
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs, ExtCtrls, StdCtrls, DateUtils, ShellAPI;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     imgWatch: TImage;
  12.     imgOriz1: TImage;
  13.     imgOriz2: TImage;
  14.     imgVert1: TImage;
  15.     imgVert2: TImage;
  16.     imgB1: TImage;
  17.     imgB2: TImage;
  18.     Timer1: TTimer;
  19.     imgNumber: TImage;
  20.     imgNumber2: TImage;
  21.     Label1: TLabel;
  22.     procedure FormCreate(Sender: TObject);
  23.     procedure Timer1Timer(Sender: TObject);
  24.     procedure Label1Click(Sender: TObject);
  25.   public
  26.     procedure DrawFigure(X, Y: Integer; aFigure: Char; aCanvas: TCanvas; aDraw: Boolean = True);
  27.     procedure DrawNumber(X, Y: Integer; aNumber: String; aCanvas: TCanvas;
  28.                          aShowLeadingZero: Boolean = False; aDraw: Boolean = True);
  29.   end;
  30.  
  31. const
  32.   figures: array ['0' .. ':'] of byte =
  33.            (119, 36, 93, 109, // bit values
  34.             46, 107, 123, 37,
  35.             127, 111, 128);
  36. var
  37.   Form1: TForm1;
  38.   lFormatSettings: TFormatSettings;
  39.   someNumber: Cardinal;
  40.  
  41. implementation
  42.  
  43. {$R *.dfm}
  44.  
  45. function GetBit(const Value: Byte; const Bit: Byte): Boolean;
  46. begin
  47.   Result := (Value and (1 shl Bit)) <> 0;
  48. end;
  49.  
  50. function LeadingZero(aNumber: String; aZeroes: Integer = 8): String;
  51. begin
  52.   while (Length(aNumber) < aZeroes) do
  53.     aNumber := '0' + aNumber;
  54.  
  55.   Result := aNumber;
  56. end;
  57.  
  58. procedure TForm1.DrawFigure(X, Y: Integer; aFigure: Char; aCanvas: TCanvas; aDraw: Boolean = True);
  59. var
  60.   bit: Byte;
  61.   DoDraw: Boolean;
  62.   lX, lY: Integer;
  63. begin
  64.   for bit := 0 to 7 do
  65.     begin
  66.       lX := X;
  67.       lY := Y;
  68.       if not GetBit(figures[aFigure], bit) // if bit is set, we draw green
  69.         then DoDraw := False               // if bit is NOT set, dark grey
  70.         else DoDraw := aDraw;
  71.  
  72.         case bit of // get piece position
  73.           0:
  74.             begin
  75.               lX := X + 3;
  76.             end;
  77.           1:
  78.             begin
  79.               lY := Y + 3;
  80.             end;
  81.           2:
  82.             begin
  83.               lX := X + imgOriz1.Width + 3;
  84.               lY := Y + 3;
  85.             end;
  86.           3:
  87.             begin
  88.               lX := X + 3;
  89.               lY := Y + imgVert1.Height + 3;
  90.             end;
  91.           4:
  92.             begin
  93.               lY := Y + imgVert1.Height + 6;
  94.             end;
  95.           5:
  96.             begin
  97.               lX := X + imgOriz1.Width + 3;
  98.               lY := Y + imgVert1.Height + 6;
  99.             end;
  100.           6:
  101.             begin
  102.               lX := X + 3;
  103.               lY := Y + imgVert1.Height * 2 + 6;
  104.             end;
  105.           7:
  106.             begin
  107.               lX := X + imgOriz1.Width div 2 + 2;
  108.               lY := Y + imgVert1.Height div 2 + 6;
  109.             end;
  110.         end;
  111.  
  112.         case bit of // display required piece - in green OR dark grey
  113.           0, 3, 6:
  114.             begin
  115.               if DoDraw
  116.                 then aCanvas.Draw(lX, lY, imgOriz1.Picture.Graphic)
  117.                 else aCanvas.Draw(lX, lY, imgOriz2.Picture.Graphic);
  118.             end;
  119.           1, 2, 4, 5:
  120.             begin
  121.               if DoDraw
  122.                 then aCanvas.Draw(lX, lY, imgVert1.Picture.Graphic)
  123.                 else aCanvas.Draw(lX, lY, imgVert2.Picture.Graphic);
  124.             end;
  125.           7:
  126.             begin
  127.               if DoDraw
  128.                 then aCanvas.Draw(lX, lY, imgB1.Picture.Graphic)
  129.                 else aCanvas.Draw(lX, lY, imgB2.Picture.Graphic);
  130.             end;
  131.         end;
  132.     end;
  133. end;
  134.  
  135. procedure TForm1.DrawNumber(X, Y: Integer; aNumber: String; aCanvas: TCanvas;
  136.                             aShowLeadingZero: Boolean = False; aDraw: Boolean = True);
  137. var
  138.   i: Integer;
  139.   zero: Boolean;
  140. begin
  141.   zero := not aShowLeadingZero;
  142.   for i := 1 to Length(aNumber) do
  143.     begin
  144.       if zero and (aNumber[i] <> '0') then
  145.         zero := False;
  146.  
  147.       if not zero
  148.         then DrawFigure(X + (i - 1) * imgOriz1.Width * 2, Y, aNumber[i], aCanvas, aDraw)
  149.         else DrawFigure(X + (i - 1) * imgOriz1.Width * 2, Y, aNumber[i], aCanvas, False);
  150.     end;
  151. end;
  152.  
  153. procedure TForm1.FormCreate(Sender: TObject);
  154. begin
  155.   GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, lFormatSettings);
  156.   lFormatSettings.TimeSeparator := ':';
  157.   lFormatSettings.ShortTimeFormat := 'hh:mm:ss';
  158.   lFormatSettings.LongTimeFormat := 'hh:mm:ss';
  159.  
  160.   imgWatch.Canvas.Brush.Color := clBlack;
  161.   imgWatch.Canvas.FillRect(imgWatch.ClientRect);
  162.   imgNumber.Canvas.Brush.Color := clBlack;
  163.   imgNumber.Canvas.FillRect(imgNumber.ClientRect);
  164.   imgNumber2.Canvas.Brush.Color := clBlack;
  165.   imgNumber2.Canvas.FillRect(imgNumber2.ClientRect);
  166. end;
  167.  
  168. procedure TForm1.Timer1Timer(Sender: TObject);
  169. begin
  170.   DrawNumber(5, 5, TimeToStr(NOW, lFormatSettings), imgWatch.Canvas, True);
  171.  
  172.   inc(someNumber);
  173.   DrawNumber(5, 5, LeadingZero(IntToStr(someNumber), 8), imgNumber.Canvas, True, True);
  174.   DrawNumber(5, 5, LeadingZero(IntToStr(someNumber), 8), imgNumber2.Canvas, False, True);
  175. end;
  176.  
  177. procedure TForm1.Label1Click(Sender: TObject);
  178. begin
  179.   ShellExecute(Handle, 'open', 'http://www.bitcell.info', nil, nil, SW_SHOWNORMAL);
  180. end;
  181.  
  182. end.


Pentru a exemplifica posibilitatile codului, programul afiseaza ora curenta si un numar incrementat de cateva ori pe secunda (afisand - sau nu - zero-urile dinaintea lui).

Screenshot:
Image

Imaginile din dreapta ceasului sunt imaginile din care sunt compuse cifrele - le puteti modifica manual si recompila programul - sau puteti modifica programul pentru a le incarca la pornire, cum se procedeaza in jocul Snake.

O alta idee pentru imbunatatirea programul ar consta in adaugarea unor noi caractere/pozitii. Acest lucru ar necesita, evident, trecerea de la byte la word sau cardinal (1 byte vs 2 sau chiar 4 bytes). Daca va simtiti norocosi, puteti chiar incerca cu 64 de bytes (int64) :P

Spor la butonat :)

Sursa si executabilul: atasate.

Bafta
6p / 1 votes
Attachments
DigitalDisplay_src.zip
(12.93 KiB) Downloaded 38 times
DigitalDisplay_exe.zip
(200.68 KiB) Downloaded 44 times
User avatar
DarkByte
11011011
 
Joined: 29 Dec 2009
Status: 140

Re: Display digital

Postby Cosmin_NTG » 20 Feb 2011, 17:53

Programul e super tare. Nu se poate face asa ceva in C++? Daca nu, ma apuc sa invat Delphi :))
0,0p / 0 votes
Thinking about solutions is better than thinking about problems
User avatar
Cosmin_NTG
Byte
 
Joined: 11 Jan 2011
Location: 192.2L1.44G
Status: 10

Re: Display digital

Postby DarkByte » 20 Feb 2011, 17:56

Bineinteles ca se poate face si in C / C++ ... ca o regula de baza, tot ce poti face in Delphi, faci si in C++ - si invers.

Din pacate, omul nostru responsabil cu tutorialele pe C / C++ are probleme cu amigdalele :D (just joking)
0,0p / 0 votes
User avatar
DarkByte
11011011
 
Joined: 29 Dec 2009
Status: 140

Re: Display digital

Postby eni4ever » 20 Feb 2011, 22:12

^^ Un exemplu ce ilustrează aceeași funcționalitate cu un QWidget din Qt (QLCDNumber) ar fi :
Image
generat de următorul cod:
  1. #include <QApplication>
  2. #include <QLCDNumber>
  3.  
  4. int main(int argc, char *argv[])
  5. {
  6.     QApplication a(argc, argv);
  7.  
  8.     QLCDNumber lcdDisplay;
  9.     QPalette lcdColPalette;
  10.     lcdColPalette.setColor(QPalette::Light, Qt::yellow);
  11.     lcdColPalette.setColor(QPalette::Dark, Qt::darkYellow);
  12.     lcdColPalette.setColor(QPalette::Foreground, Qt::green);
  13.     lcdColPalette.setColor(QPalette::Background, Qt::black);
  14.     lcdDisplay.setPalette(lcdColPalette);
  15.     lcdDisplay.display(1234);
  16.     lcdDisplay.show();
  17.  
  18.     return a.exec();
  19. }

cu fel și fel de alte configurații, desigur!

Nu este ca și cum l-ai face tu "from scratch", dar hei ... își face treaba, right? :)

P.S: \/ După cum observi, maximize-ul nu e dezafectat! ;)
0,0p / 0 votes
Last edited by eni4ever on 21 Feb 2011, 01:57, edited 2 times in total.
Image

"Rațiunea vine în umbre scurte numite suferințe." Victor Adăscăliței
"Bender: Anything less than immortality is a complete waste of time.
Zoidberg: Then suicide it is! Step into my office ..." Futurama S06E06
User avatar
eni4ever
DWord
 
Joined: 03 Jan 2010
Location: Timișoara
Status: 57.83

Re: Display digital

Postby DarkByte » 21 Feb 2011, 01:38

Offtopic
0,0p / 0 votes
User avatar
DarkByte
11011011
 
Joined: 29 Dec 2009
Status: 140

Re: Display digital

Postby Cosmin_NTG » 21 Feb 2011, 15:19

eni4ever wrote:^^ Un exemplu ce ilustrează aceeași funcționalitate cu un QWidget din Qt (QLCDNumber) ar fi :
Image
generat de următorul cod:
  1. #include <QApplication>
  2. #include <QLCDNumber>
  3.  
  4. int main(int argc, char *argv[])
  5. {
  6.     QApplication a(argc, argv);
  7.  
  8.     QLCDNumber lcdDisplay;
  9.     QPalette lcdColPalette;
  10.     lcdColPalette.setColor(QPalette::Light, Qt::yellow);
  11.     lcdColPalette.setColor(QPalette::Dark, Qt::darkYellow);
  12.     lcdColPalette.setColor(QPalette::Foreground, Qt::green);
  13.     lcdColPalette.setColor(QPalette::Background, Qt::black);
  14.     lcdDisplay.setPalette(lcdColPalette);
  15.     lcdDisplay.display(1234);
  16.     lcdDisplay.show();
  17.  
  18.     return a.exec();
  19. }

cu fel și fel de alte configurații, desigur!

Nu este ca și cum l-ai face tu "from scratch", dar hei ... își face treaba, right? :)

P.S: \/ După cum observi, maximize-ul nu e dezafectat! ;)


Imi puteti spune ce compilator/mediu ati utilizat? De exemplu in MinGW imi da 14 erori de tot felul (sintaxa, nedeclarare...s.a.m.d).
0,0p / 0 votes
Thinking about solutions is better than thinking about problems
User avatar
Cosmin_NTG
Byte
 
Joined: 11 Jan 2011
Location: 192.2L1.44G
Status: 10

Re: Display digital

Postby andreiandreiq » 21 Feb 2011, 21:12

@Cosmin_NTG: Uita-te pe aici (click). Si baga de seama ca a zis: "Un exemplu ce ilustrează aceeași funcționalitate cu un QWidget din Qt (QLCDNumber)".
0,0p / 0 votes
Image
User avatar
andreiandreiq
Word
 
Joined: 30 Dec 2009
Status: 33.33

Re: Display digital

Postby RaverX » 22 Feb 2011, 16:46

Frumos, dar prima data cand am vazut titlul am crezut ca se poate controla un display digital prin portul paralel cu programelul. Oh well... maybe next time ? O:-)
0,0p / 0 votes
User avatar
RaverX
Bit
 
Joined: 06 Jan 2010
Status: 0

Re: Display digital

Postby smith » 06 May 2011, 16:10

Well... ask enigma (eni4ever), poate are inima mare și face el un tutorial de genul ăla :P
0,0p / 0 votes
Ilea Cristian
User avatar
smith
Enum
 
Joined: 29 Dec 2009
Location: Cluj-Napoca
Status: 82

Re: Display digital

Postby eni4ever » 07 May 2011, 20:57

^ Roger!: Nu prea este recomandat să umblăm pe la porturi așa, cum ni se cășună nouă, mai ales dacă ținem la unitatea noastră. Totuși, după un pic de înțelegere a fenomenului fizic și cu puține măsuri de siguranță, poate vom aborda această temă într-o zi :).
0,0p / 0 votes
Image

"Rațiunea vine în umbre scurte numite suferințe." Victor Adăscăliței
"Bender: Anything less than immortality is a complete waste of time.
Zoidberg: Then suicide it is! Step into my office ..." Futurama S06E06
User avatar
eni4ever
DWord
 
Joined: 03 Jan 2010
Location: Timișoara
Status: 57.83


Return to Tutoriale Delphi

Who is online

Users browsing this forum: No registered users and 0 guests

cron