I am drawing onformpaint event the same bitmap in diffrent places on the form what i would like to do is add a drag and drop functionality to those bitmaps to enable the user to place them as he wishes on the form.I have an idea but it seems quite rudimentary and i don't want to put useless effort.I would appreciate some implementation ideas from you guys.
Thanks.
P.S I would like to implement an OnClick event over those bitmaps too
Unless you have specific reasons to do so, I would not draw the bitmaps in the OnFormPaint handler as this complicates what you want to achieve very much. Instead you could use Timages on your form, and your second requirement of having OnClick handlers is solved. Drag and Drop of TIamges should not be too complicated either when dealing with TImage components.
Edit:
Inspired by Bruce's answer, I came up with a working sample using the techniques in his mentioned example. I subclassed a TPanel and a TImage to achieve the desired effect. It's important that the TImage is parented in the TPanel. Note, that this is just a quick and dirty sample, no checks ect (like if the parent of the Timahe really is a TParent). In order for the example to work, drop a TPanel on a form and a Timage on the TPanel.
unit Unit66;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, jpeg;
const
sizeBorder = 2;
sc_SizeLeft = $F001; { these are the variations }
sc_SizeRight = $F002; { on the SC_SIZE value }
sc_SizeTop = $F003;
sc_SizeTopLeft = $F004;
sc_SizeTopRight = $F005;
sc_SizeBottom = $F006;
sc_SizeBottomRight = $F008;
sc_SizeBottomLeft = $F007;
sc_DragMove = $F012;
type
TPanel = class(ExtCtrls.TPanel)
public
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
end;
TImage = class(ExtCtrls.TImage)
public
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
end;
TForm66 = class(TForm)
Panel1: TPanel;
Image1: TImage;
procedure Image1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form66: TForm66;
implementation
{$R *.dfm}
{ TImage }
procedure TPanel.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
begin
if Button = mbLeft then
begin
ReleaseCapture;
if (X >= Width - sizeBorder) And NOT((Y <= sizeBorder) or (Y >= Height - sizeBorder)) then
Self.Perform(WM_SysCommand, sc_SizeRight, 0)
else if Not((X <= sizeBorder) or (X >= Width - sizeBorder)) And (Y <= sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeTop, 0)
else if (X <= sizeBorder) And (Y <= sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeTopLeft, 0)
else if (X >= Width - sizeBorder) and (Y <= sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeTopRight, 0)
else if Not((X <= sizeBorder) or (X >= Width - sizeBorder)) And (Y >= Height - sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeBottom, 0)
else if (Y >= Height - sizeBorder) And (X <= sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeBottomLeft, 0)
else if (Y >= Height - sizeBorder) and (X >= Width - sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeBottomRight, 0)
else if Not((Y <= sizeBorder) or (Y >= Height - sizeBorder)) And (X <= sizeBorder) then
Self.Perform(WM_SysCommand, sc_SizeLeft, 0)
else
begin
Self.Perform(WM_SysCommand, sc_DragMove, 0);
end;
end;
end;
procedure TPanel.MouseMove(Shift: TShiftState; X, Y: integer);
begin
if (X <= sizeBorder) or (X >= Width - sizeBorder) then
begin
if (Y >= Height - sizeBorder) then
begin
if (X >= Width - sizeBorder) then
Cursor := crSizeNWSE
else
Cursor := crSizeNESW;
end
else if (Y <= sizeBorder) then
begin
if (X >= Width - sizeBorder) then
Cursor := crSizeNESW
else
Cursor := crSizeNWSE;
end
else
Cursor := crSizeWE;
end
else if (Y <= sizeBorder) or (Y >= Height - sizeBorder) then
begin
Cursor := crSizeNS;
end
else
Cursor := crDefault;
end;
procedure TForm66.Image1Click(Sender: TObject);
begin
ShowMessage('Image clicked');
end;
{ TImage }
type
TWinControlHack = class(TWinControl);
procedure TImage.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
begin
if ssCtrl in Shift then
TWinControlHack(Parent).MouseDown(Button, Shift, X, Y);
end;
procedure TImage.MouseMove(Shift: TShiftState; X, Y: integer);
begin
TWinControlHack(Parent).MouseMove(Shift, X, Y);
end;
end.
Here is a useful example that will let you move or resize TCustomControl descendents at run time.
I think your best option is to use a TImage instead of custom drawing. As iamjoosy points out, the above example won't work with TGraphicControls. There are some freeware components that might be more helpful here and here.
Related
Please help me to convert this PL/SQL into PostgreSQL. Thank you very much.
Prime Numbers
CREATE TABLE n (n NUMBER);<br/>
CREATE OR REPLACE PROCEDURE prime_number (n NUMBER)<br/>
IS <br/>
prime_count NUMBER := 0;<br/>
y VARCHAR2 (1) := 'N';<br/>
BEGIN<br/>
IF n >= 1
THEN
prime_count := 1;
INSERT INTO n
VALUES (2);
END IF;
IF n >= 2
THEN
prime_count := 2;
INSERT INTO n
VALUES (2);
END IF;
IF n >= 3
THEN
FOR i IN 4 .. n * n * n
LOOP
y := 'N';
FOR j IN 2 .. CEIL (SQRT (i))
LOOP
IF (MOD (i, j) = 0)
THEN
y := 'Y';
EXIT;
END IF;
END LOOP;
IF (y = 'N')
THEN
INSERT INTO n
VALUES (i);
COMMIT;
prime_count := prime_count + 1;
EXIT WHEN prime_count = n;
END IF;
END LOOP;
END IF;<br/>
END;
BEGIN<br/>
prime_number (1000000);<br/>
END;
I have a custom form (custom shape and transparency) with no borders (BorderStyle: bsNone). It has a background image, a normal TImage Component. It want the form to be draggable from the TImage. Is that possible? I'm using Lazarus 1.2.6 (FPC ver.: 2.6.4).
This is what my custom form looks like on an empty desktop: Image.
Here is a cross-platform solution:
type
TForm1 = class(TForm)
Image1: TImage;
procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var PX, PY: Integer;
MouseIsDown: Boolean;
procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then begin
MouseIsDown := True;
PX := X;
PY := Y;
end;
end;
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if MouseIsDown then begin
SetBounds(Form1.Left + (X - PX), Form1.Top + (Y - PY), Form1.Width, Form1.Height);
end;
end;
procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
MouseIsDown:=False;
end;
Dragging the TImage will cause the Form to be dragged.
Assuming you are using windows, this is the general way to do what you are asking:
uses
Windows;
type
TForm1 = class(TForm)
private
procedure WMNCHitTest(var Msg: TWMNCHitTest); message WM_NCHITTEST;
end;
procedure TForm1.WMNCHitTest(var Msg: TWMNCHitTest);
begin
Msg.Result := HTCAPTION
end;
I'm implementing RSA encryption and need to generate random 1024-bit primes.
I can't use INTEGER signals because of the limit, and so I'm using STD_LOGIC_VECTOR and convert it to UNSIGNED when I need to perform arithmetic operations.
I began by using UNIFORM to generate 32 random 32-bit numbers which I then copy over into a 1024-bit STD_LOGIC_VECTOR.
I then set the most significant and least significant bits to '1' to ensure it is 1024-bits and odd.
I then check for primality using an implementation of the Miller Rabin algorithm, which is where my problem lies.
This is where I generate the random primes:
function GEN_1024_PRIME return STD_LOGIC_VECTOR is
VARIABLE s1, s2 : POSITIVE;
VARIABLE random : REAL;
VARIABLE small_random : STD_LOGIC_VECTOR (31 downto 0);
VARIABLE large_random : STD_LOGIC_VECTOR (1023 downto 0);
VARIABLE prime : STD_LOGIC := '0';
begin
while prime /= '1' loop
for I in 0 to 31 loop
UNIFORM(s1, s2, random);
small_random := STD_LOGIC_VECTOR(to_unsigned(INTEGER(TRUNC(random * REAL(2147483647))), 32));
large_random (I*32 + 31 downto I*32) := small_random;
end loop;
large_random(0) := '1';
large_random(1023) := '1';
prime := MILLER_RABIN (large_random);
end loop;
return large_random;
end function;
And my implementation of Miller Rabin:
function MILLER_RABIN (prime : STD_LOGIC_VECTOR (1023 downto 0)) return STD_LOGIC is
VARIABLE t : INTEGER := 4;
VARIABLE temp, r, a, x, j, n: UNSIGNED (1023 downto 0);
VARIABLE small_random : UNSIGNED (31 downto 0);
VARIABLE large_random : UNSIGNED (1023 downto 0);
VARIABLE s1, s2 : POSITIVE;
VARIABLE random : REAL;
begin
n := UNSIGNED(prime);
if n MOD 2 = 0 OR n MOD 3 = 0 then
return '0';
else
-- calculate n - 1 = 2^s * r such that r is odd
r := n - 1;
while r MOD 2 = 0 loop
r := r / 2;
end loop;
for I in 1 to t loop
-- choose random a, 2 <= a <= n-2
for I in 0 to 31 loop
UNIFORM(s1, s2, random);
small_random := to_unsigned(INTEGER(TRUNC(random * REAL(2147483647))), 32);
large_random (I*32 + 31 downto I*32) := small_random;
end loop;
a := large_random;
temp := r;
x := MOD_3(a, temp, n);
while (temp /= (n - 1) AND x /= 1 AND x /= (n - 1)) loop
x := (x * x) MOD n;
temp := temp * 2;
end loop;
if x /= (n - 1) AND temp MOD 2 = 0 then
return '0';
end if;
end loop;
return '1';
end if;
end function;
function MOD_3 (a, b, c : UNSIGNED (1023 downto 0)) return UNSIGNED is
VARIABLE x : UNSIGNED (1023 downto 0) := TO_UNSIGNED(1, 1024);
VARIABLE y : UNSIGNED (1023 downto 0) := a;
VARIABLE b_temp : UNSIGNED (1023 downto 0) := b;
begin
while b_temp > 0 loop
if b_temp MOD 2 = 1 then
x := (x * y) MOD c;
end if;
y := (y * y) MOD c;
b_temp := b_temp / 2;
end loop;
return x MOD c;
end function;
I convert the input to UNSIGNED in order to perform arithmetic operations, which seemed like it would work until I realized there will be instances in which the product of 2 values will be larger than 1024 bits. For example, in this while loop:
while (temp /= (n - 1) AND x /= 1 AND x /= (n - 1)) loop
x := (x * x) MOD n;
temp := temp * 2;
end loop;
The resultant of temp := temp * 2; is 2048 bits.
I feel like I could get this to work by messing around with the sizes of my UNSIGNED variables, but I think it is getting messier than it needs to be, so I'm wondering if I am approaching this the wrong way? Is there a simpler way to generate 1024-bit primes? Is there another primality test that would be better suited for my problem?
I am searching for a macro, constant or attribute, whatever it is, replaces "(x downto y)". To explain in detail for example complex numbers,
there is a generic value WIDTH,
signal num : std_logic_vector(2*WIDTH downto 0);
**pseudo**
re = 2*WIDTH-1 downto WIDTH;
im = WIDTH-1 downto 0;
**pseudo**
x <= num(re);
y <= num(im); etc
also it could be some attribute like range. eg
x <= num(num're);
y <= num(num'im);
I use it a lot and it should be great for better readability and writing clean code
A subtype can be used to declare an integer range like:
-- **pseudo** re = 2*WIDTH-1 downto WIDTH; im = WIDTH-1 downto 0; **pseudo**
subtype re is natural range 2*WIDTH-1 downto WIDTH;
subtype im is natural range WIDTH-1 downto 0;
Then it is possible to do:
x <= num(re);
y <= num(im);
With x and y declared as std_logic_vector(WIDTH-1 downto 0), or std_logic_vector(re) and std_logic_vector(im).
Btw. num should probably have highest index as 2*WIDTH-1, and not 2*WIDTH (off-by-one error).
Maybe not exactly what you had in mind, but a VHDL record would seem to be a good fit for what you are trying to do.
You define your record type:
type mycomplex_t is record
re : std_logic_vector(WIDTH-1 downto 0);
im : std_logic_vector(WIDTH-1 downto 0);
end record;
Then, you declare your signal to be of this type:
signal num : mycomplex_t;
And you use it as such:
x <= num.re;
y <= num.im;
You can also assign it like this :
num <= (re => x2, im => y2);
Or, like this:
num.re <= x2;
num.im <= y2;
Or all at once from another signal of the same type:
signal other_complex : mycomplex_t;
-- (...)
num <= other_complex;
I try code published by Freddie Bell at What is the best way to make a Delphi Application completely full screen? question, as is what i needed.
I also set minimun size to be the original size.
with msg.MinMaxInfo^.ptMinTrackSize do
begin
// maximum size when maximised
x := original_width;
y := original_height;
end;
And in Form OnShow event:
original_width := Width;
original_height := Height;
But i have this issue:
- Mainform has two panels, one of it is aligned as alRight, the other as alLeft; so the working_area is the space between the panels. Mainform has no borders and it is fully maximizad to the work area with
SystemParametersInfo(SPI_GETWORKAREA, 0, #working_desktop, 0);
When i move the form, it keeps inside the working_area between the panels.
When i size the form, it keeps inside that working_area.
But, when i size the form in either way (left or right) passing the edge of the working_area, the form increased its size to the other side. i.e., if the form is on left edge, and you select it to resize it and you move to the left (towards the edge), the form increase its width to the right (but it stop at right edge!).
I try with some code (catching WMSIZE or WMSIZING), but i can prevent that behavior?
Thanks you all in advance!
EDIT (David Heffernan): The key code appears to be in this unit.
unit uFormularios;
interface
uses Windows, Messages, Forms, DBGrids, StdCtrls, Menus, Graphics, ComCtrls;
type
TForm_en_ventana = class(TForm)
private
ancho_original, alto_original: integer;
procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
procedure WMWindowPosChanging(Var Msg: TWMWindowPosChanging); Message WM_WINDOWPOSCHANGING;
procedure WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo); message WM_GETMINMAXINFO;
procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
end;
TForm_en_ventana_centrado = class(TForm_en_ventana)
private
ancho_original, alto_original: integer;
procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
end;
procedure MaximizarFormulario(var F; MaximaAltura: integer = 0; MaximoAncho: integer = 0; Centrado: boolean = TRUE);
procedure InicializarVentanaTrabajo(const izq, der, arr, aba: integer);
var ESPACIO_DE_TRABAJO,
VENTANA_DE_TRABAJO : TRect;
implementation
procedure MaximizarFormulario(var F; MaximaAltura: integer = 0; MaximoAncho: integer = 0; Centrado: boolean = TRUE);
begin
LockWindowUpdate(TForm(F).Handle);
TForm(F).Left := ESPACIO_DE_TRABAJO.Left;
if MaximoAncho = 0 then
TForm(F).Width := ESPACIO_DE_TRABAJO.Right
else
begin
if ESPACIO_DE_TRABAJO.Right < MaximoAncho then
TForm(F).Width := ESPACIO_DE_TRABAJO.Right
else
TForm(F).Width := MaximoAncho;
end;
TForm(F).Top := ESPACIO_DE_TRABAJO.Top;
if MaximaAltura = 0 then
TForm(F).Height := ESPACIO_DE_TRABAJO.Bottom
else
begin
if ESPACIO_DE_TRABAJO.Bottom < MaximaAltura then
TForm(F).Height := ESPACIO_DE_TRABAJO.Bottom
else
TForm(F).Height := MaximaAltura;
end;
if ((MaximoAncho <> 0) or (MaximaAltura <> 0)) and (Centrado) then
begin
TForm(F).Left := (ESPACIO_DE_TRABAJO.Right - TForm(F).Width ) div 2;
TForm(F).Top := (ESPACIO_DE_TRABAJO.Bottom - TForm(F).Height) div 2;
end;
LockWindowUpdate(0);
end;
procedure InicializarVentanaTrabajo(const izq, der, arr, aba: integer);
begin
VENTANA_DE_TRABAJO.Left := izq;
VENTANA_DE_TRABAJO.Right := der;
VENTANA_DE_TRABAJO.Top := arr;
VENTANA_DE_TRABAJO.Bottom := aba;
end;
procedure TForm_en_ventana.WMWindowPosChanging(var Msg: TWMWINDOWPOSCHANGING);
begin
with Msg.WindowPos^ do
{
x: int; The position of the left edge of the window.
y: int; The position of the top edge of the window.
cx: int; The window width, in pixels.
cy: int; The window height, in pixels.
}
begin
if x <= VENTANA_DE_TRABAJO.Left then
x := VENTANA_DE_TRABAJO.Left;
if x + cx >= VENTANA_DE_TRABAJO.Right then
x := (VENTANA_DE_TRABAJO.Right) - cx;
if y <= VENTANA_DE_TRABAJO.Top then
y := VENTANA_DE_TRABAJO.Top;
if y + cy >= VENTANA_DE_TRABAJO.Bottom then
y := (VENTANA_DE_TRABAJO.Bottom) - cy;
end;
end;
Procedure TForm_en_ventana.WMGetMinMaxInfo(Var msg: TWMGetMinMaxInfo);
begin
inherited;
with msg.MinMaxInfo^.ptMaxPosition do
begin
// position of top when maximised
x := VENTANA_DE_TRABAJO.Left;
y := VENTANA_DE_TRABAJO.Top;
end;
with msg.MinMaxInfo^.ptMaxSize do
begin
// width and height when maximized
x := VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left;
y := VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top;
end;
with msg.MinMaxInfo^.ptMaxTrackSize do
begin
// maximum size when maximised
x := VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left;
y := VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top;
end;
with msg.MinMaxInfo^.ptMinTrackSize do
begin
// maximum size when maximised
x := ancho_original;
y := alto_original;
end;
end;
procedure TForm_en_ventana.WMSysCommand(var Msg: TWMSysCommand);
begin
if Msg.CmdType and $FFF0 = SC_MINIMIZE then
Application.Minimize
else
inherited;
end;
procedure TForm_en_ventana.WMShowWindow(var Message: TWMShowWindow);
begin
ancho_original := Width;
alto_original := Height;
end;
procedure TForm_en_ventana_centrado.WMShowWindow(var Message: TWMShowWindow);
begin
ancho_original := Width;
alto_original := Height;
Left := (((VENTANA_DE_TRABAJO.Right - VENTANA_DE_TRABAJO.Left) - Width) div 2) + VENTANA_DE_TRABAJO.Left;
Top := (((VENTANA_DE_TRABAJO.Bottom - VENTANA_DE_TRABAJO.Top) - Height) div 2) + VENTANA_DE_TRABAJO.Top;
end;
initialization
SystemParametersInfo(SPI_GETWORKAREA, 0, #ESPACIO_DE_TRABAJO, 0);
VENTANA_DE_TRABAJO := ESPACIO_DE_TRABAJO;
end.
Your handler for WM_WINDOWPOSCHANGING is fine for moving operations but needs to be different for sizing operations. You can't detect those from within that message handler so you need an alternative. Instead use WM_SIZING and WM_MOVING like this:
procedure WMSizing(Var msg: TMessage); message WM_SIZING;
procedure WMMoving(Var msg: TMessage); message WM_MOVING;
....
procedure TForm_en_ventana.WMSizing(var msg: TMessage);
var
R: PRect;
begin
R := PRect(msg.LParam);
R.Left := Max(R.Left, VENTANA_DE_TRABAJO.Left);
R.Right := Min(R.Right, VENTANA_DE_TRABAJO.Right);
R.Top := Max(R.Top, VENTANA_DE_TRABAJO.Top);
R.Bottom := Min(R.Bottom, VENTANA_DE_TRABAJO.Bottom);
end;
procedure TForm_en_ventana.WMMoving(var msg: TMessage);
var
R: PRect;
dx, dy: Integer;
begin
R := PRect(msg.LParam);
dx := 0;
dy := 0;
if R.Left<VENTANA_DE_TRABAJO.Left then
dx := VENTANA_DE_TRABAJO.Left-R.Left;
if R.Right>VENTANA_DE_TRABAJO.Right then
dx := VENTANA_DE_TRABAJO.Right-R.Right;
if R.Top<VENTANA_DE_TRABAJO.Top then
dy := VENTANA_DE_TRABAJO.Top-R.Top;
if R.Bottom>VENTANA_DE_TRABAJO.Bottom then
dy := VENTANA_DE_TRABAJO.Bottom-R.Bottom;
OffsetRect(R^, dx, dy);
end;
You will need to remove the WM_WINDOWPOSCHANGING altogether.