Keresés
Hírlevél
 
Kiemelt témák
»10 éves a prog.hu
»Párhuzamos programozás
»Párhuzamos végrehajtás == szemléletváltás!
Állás/munka
»Tanárt keresek
»Port.hu film tartalmának kinyerése
»PHP programozó kerestetik
»Fejlesztői megbízásokat/munkát keresek
»Senior .Net fejlesztő szabad kapacitással
» több téma
Tudástár
?PHP if-nél megakadtam
? torrent file helyett txt-t
?PHP:keresés szó szerint...
Mobilinternet használata robotokban
?Delphi Form méretezési probléma
?HelpProvider alkalmazás .HLP fájlban
2 oldalas form
SetFocus hatástalan
?XP-n megy Win7-en megakad (Delphi)
?Hiányos mp3 hallgatás telefonról! C#
A legalsó scrollTop értéket nem veszi figyelembe
3 dív pozicionálása (2 egymás mellé, 1 ezek alá)
?Curl login Joomla-ba (PHP)
*Java Axis webservice file küldés és fogadás
?C# scrollozható form
» több téma
Társalgó
»Az általános műveltség része kellene, hogy legyen a programozni tudás?
»Get flood elleni védekezés
»Újra programozni fog a Facebook alapítója és multimilliárdos elnöke
»Firebird - Több adatbázis vagy egy?
»Clipper kontra XP
»Webshop ár kb...
»Hogy működik egy apróhirdető oldal (MySQL)?
»Körlevél script PHP + MySQL
»New project probléma VS 2010 C#
»Kezdőknek:grafikus felület választás
» több téma
ASPC#C++CSSDelphiFlashJavaJavaScriptPascalPerlPHPPythonuniPaaSVisual BasicVisual C++  »    

Tudástár

»

Delphiben gombok átfedésének tiltása

»

Delphiben gombok átfedésének tiltása

nyitotta: dgyula, idő: 2012.02.07., moderátor: netangel, megoldás elfogadva: 2012.03.04. 20:48
  Értesítés változás esetén Felvétel kedvencekhez Küldés emailben Nyomtatható verzió

Kategóriák:Programozási nyelvek » Delphi

Kulcsszavak:
Sorrend:
Időzóna:
Blokkméret:
Oszd meg másokkal is!
Sziasztok!

Futás időben hozok létre gombokat egy panel-en és később azokat tetszőlegesen át lehet rendezni és a gombok között 2 féle méretű van. Hogyan lehetne azt megcsinálni, hogy a gombok ne takarhassák be egymást? (Azaz ne lehessen egyik gombot a másikra ráhúzni, valamint ne is tudjon mondjuk 2 pixelnél közelebb kerülni a másikhoz.)
Szerintem azt hagynod kellene hogy ráhúzhassa, mert ha olyan területre akarják húzni a gombot, ami előtt egy rakás másik gomb van, akkor ki kellene kerülnie valamerre az egészet, nem tudja felettük elhúzni. Inkább akkor nézd meg, hogy hol van az áthúzott gomb, amikor elengedik. Ha takarja valami, akkor ahhoz képest igazítod valahova. Persze, akkor újra meg kell vizsgálnod, hogy nehogy most meg egy másik gomb takarja. Vagy eleve egy olyan területet keresel, ahol nincs semmi. A panel gombjait egy for ciklussal be tudod járni.

for i := 0 to panel.ControlCount - 1 do
begin
  if panel.Controls[i] is TButton then  // ha gomb
  begin
    // ide jöhet a kód, amivel megvizsgálod, hogy takarják-e egymást
  end;
end;
előzmény
Le kell programozni.Elteszed a gombok paramétereit egy tömbbe.
Minden gomb helyét tudod:
Left,Top
Minden gomb szélességét, magasságát tudod:
Width, Height. előzmény
Képzelj el egy mozaikot. Ennek megfelelően nem lehetnek a gombok takarásban. Áthúzni felette miért nem lehet? Én arra gondoltam, hogy amikor elengedi a gombot, akkor vizsgálom hogy van-e ott gomb és ha van, akkor arrébb tolom 1 pixelt és megint megnézem. előzmény
Ettől tartok én is. Van ötleted hogyan tudom megcsinálni?

Mert az oké, hogy meg tudom nézni hogy x,y pontban van-e valami, de ha pl. x+1,y pontban van, akkor mi van? Vagy csináljak egy tömböt amiben a panel minden létező x,y koordinátája megvan és abban jelzem a lefoglalt koordinátákat, majd azt vizsgálom hogy a komponensem koordinátái szerepelnek-e az adott koordináták között? De hogyan? előzmény
Úgy értettem, hogy miközben húzza, ne vizsgáld, mert akkor nem fogja tudni áthúzni egy másik gomb felett. Amikor elengedi, akkor lehet vizsgálni. Ha ilyen mozaikszerűen akarod (ezt hittem, bárhol lehetnek), akkor miért nem hozol létre egy tömböt, ami az egyes négyzetekben lévő gombokat tárolják, meg a terület koordinátáit? Elengedéskor csak meg kell keresni a tömbben a koordinátáknak megfelelő elemet, és megnézni, hogy van-e benne valami. Ha igen, akkor keresel a közelében egy üreset, és berakod oda. előzmény
Valami ilyesmin gondolkoztam én is, csak a gomb méretek eltérőek. előzmény
Legyen a mozaik egy-egy eleme akkora, hogy a legnagyobb gomb beleférjen. Utána a kisebb gombokat csak el kell rendezni benne valahogy. előzmény
A valahogyig én is lejutottam már. Csak az kellene hogy pontosan hogyan. előzmény
Tényleg nincs valami property amit ha bekapcsolok, akkor "egy szintre" kerülnek az adott komponensek, azaz legfelülre? előzmény
Létrehozol egy rekord típust. Ebben eltárolod a mozaik egy elemének az adatait, mint Left, Top, Width, Height (talán Right és Bottom célszerűbb lenne). Plusz eltárolod benne azt a gombot, amelyik épp benne van. Ha nincs benne semmi, akkor ennek az értéke nil. Készítesz egy tömböt, ami annyi elemű, amennyi elemet akarsz a mozaikban. Utána az elemeknek megadod, hogy a képernyőn melyik területhez tartoznak. Ha egy gombot húznak valahova, akkor elkezded végigjárni a tömböt, és megnézed, hogy melyik elem területén engedték el. Ha ott a gomb = nil, akkor mehet oda. Értelemszerűen tudni kell, hogy honnan húzták a gombot, mert ott nil-re kell állítani a gombot. előzmény
Használj ToolBar-t, az megoldja a problémád. Kivéve azt, hogy azon minden gomb egyforma nagyságú. Állítsd True-ra a Customizable property-jét, a gomboknak meg van egy Marked property-ja, amivel tudod jelölni, ha kiválasztanak egyet. Húzogatni sem kell a gombokat, mert ha kétszer rákattint a user, akkor úgy állítja magának a sorrendet, ahogy akarja. előzmény
Ez eddig oké, de mi van ha csak a gomb 1/3-ig húzza? pl. egy 3x3-as pixelű gomb esetén 9 pontból áll a gomb. Vegyünk egy 6x6-os hátteret (rácsot) amin lehet toligálni. Ekkor 4x4=16 féle módon lehet elhelyezni ezen a rácson. Értelem szerűen minél kisebb a gomb és nagyobb a rács a lehetőségek száma úgy nő. És akkor nekem minden egyes lehetőséget fel kellene töltenem egy tömbbe és az vizsgálni?? 542x809-as jelenleg a rácsom amint tetszőleges számú gomb helyezhető el mondjuk és tetszőleges arányban a kicsi és nagy gombok. előzmény
Ha 6x6-os a rács, akkor egy 36 elemű tömb kell. Ha egy terület 5x5 pixeles, akkor a tömb első elemében ez lesz: Left = 1, Top = 1, Bottom = 6, Right = 6, Gomb = nil. Ha az elengedéskor mondjuk a gomb bal felső sarka ezen a területen belül van, akkor mehet oda. gomb.Left := elem.Left és gomb.Top := elem.Top. Vagy ehhez még hozzáadsz 1 pixelt, ha akarsz egy kis helyet kihagyni. Ezért írtam, hogy 5x5-ös a terület. Lesz körbe egy pixel. előzmény
Ne vicceljetek már azokkal a tömbökkel! Itt egy példa. Minden gombnak létrehozol egy a területének megfelelő region-t, majd amikor a gombot mozgatod, a RectInRegion api-val ellenőrzöd, hogy fedi-e valamelyiket. Ebből a kódból kiindulhatsz. Tegyél egy gombot a formra és annak implementáld a MouseMove és MouseDown eseményét, úgy ahogy itt van:

...
type
  TForm1 = class(TForm)
  ...

const
  PIC_NUM = 5;

var
  Form1: TForm1;
  Rgns: array[0..PIC_NUM-1] of HRGN;
  fx: Integer;
  fy: Integer;
  BrActive: HBRUSH;
  BrInactive: HBRUSH;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  //a Rgns minden elemet es a ket brush objektumot fel kell szabaditani az
  //OnCloseQueryben a DeleteObject() apival!
  Rgns[0] := CreateRectRgn( 0, 0, Width, Height );
  Rgns[1] := CreateRectRgn( 50, 50, 200, 300 );
  Rgns[2] := CreateRectRgn( 210, 250, 300, 350 );
  Rgns[3] := CreateRectRgn( 300, 100, 500, 200 );
  Rgns[4] := CreateRectRgn( 350, 250, 400, 400 );
  BrActive := CreateSolidBrush( RGB( 255, 0, 0 ) );
  BrInactive := CreateSolidBrush( RGB( 200, 200, 200 ) );

  for i := 1 to pic_num - 1 do
    CombineRgn( Rgns[0], Rgns[0], Rgns[i], RGN_XOR );
end;

procedure TForm1.Button1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  rt: TRect;
  i: Integer;
begin
  if ssLeft in Shift then
  begin
    Button1.Left := Button1.Left + x - fx;
    Button1.Top  := Button1.Top  + y - fy;
    GetWindowRect( button1.Handle, rt );
    Windows.ScreenToClient( handle, rt.TopLeft );
    Windows.ScreenToClient( handle, rt.BottomRight );

    for i := 1 to PIC_NUM -1 do
    begin
      if RectInRegion( Rgns[i], rt ) then
        // hoppsz, fedes van!
        FillRgn( Form1.Canvas.Handle, Rgns[i], BrActive )
      else
        FillRgn( Form1.Canvas.Handle, Rgns[i], BrInactive );
    end;
  end;
end;

procedure TForm1.Button1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  fx := x;
  fy := y;
end;
Fogd a gombot és sétáltasd a formon!

Tehát neked létre kell hozni minden egyes gombodnak egy regiont(lásd CreateRectRgn) amelyeknek megadod egyenként a gombok koordinátáit. Példának ott a FormCreate esemény.
Ha a gombod egyetlen pixele is fedi valamelyik másikat, akkor rögtön látni fogod.

<<Innen>> inspirálódtam. előzmény
Köszi, a formcreate-s részt nem értem.

Ez a részt pl hogy is kell értelmezni? Az Rgns[0] az pl a button1 koordinátáit kell tartalmazza? Az első a top, a második a left a harmadik a width és a negyedik a height értéke? Én ezt a részt a panel1 onClick eseményéhez szeretném rendelni. Úgy is megy?

  Rgns[0] := CreateRectRgn( 0, 0, Width, Height );
  Rgns[1] := CreateRectRgn( 50, 50, 200, 300 );
  Rgns[2] := CreateRectRgn( 210, 250, 300, 350 );
  Rgns[3] := CreateRectRgn( 300, 100, 500, 200 );
  Rgns[4] := CreateRectRgn( 350, 250, 400, 400 );

Ez a rész festegeti a négyszöget az RGB()-ben megadott színre. De nekem nem festenie kellene - sőt ne is fesse! - hanem az hogy annyi pixelt ugorjon el hogy ne érjen hozzá a már ott lévő komponenshez. Ez is megoldható valahogy? Vagy legalább ne engedje lerakni oda, hanem ugorjon akkor inkább vissza a kiindulási koordinátákra.

  BrActive := CreateSolidBrush( RGB( 255, 0, 0 ) );
  BrInactive := CreateSolidBrush( RGB( 200, 200, 200 ) );

Ez mit is csinál pontosan?
  for i := 1 to pic_num - 1 do
    CombineRgn( Rgns[0], Rgns[0], Rgns[i], RGN_XOR );
end;

Amúgy felraktam és szépen maszálgat, csak azt nem tudom ebből hogy lesz az ami nekem kellene.

előzmény
Köszi, a formcreate-s részt nem értem.
Most magyarázzam én el? Írd be a google-be CreateRectRgn és amit a microsoft oldalán látsz találatot, olvasd el.

Az Rgns[0] az pl a button1 koordinátáit kell tartalmazza?
Nem, ki mondta ezt? Width, Height semmilyen minősítés nélkül, kire vonatkozik?

De nekem nem festenie kellene - sőt ne is fesse! Akkor ne fesd. De te nem látod, hogy ez egy szemléltető példa arra, hogy milyen egyszerű megnézni, hogy egy téglalap ott van-e ahol kellene legyen. Ha ebből nem érted mit kellene kivenned, akkor hagyd abba az egészet. előzmény
Leírásként megtaláltam ezt:
http://www.codexonline.hu/CodeX2/alap/del/for/regi2.htm

Meg elolvastam ezt is:
http://msdn.microsoft.com/en-us/library/dd183514(v=vs.85).aspx

De nem értem, hogy honnan tudom a régió koordinátáit meg. Mert ugye delphiben tudom az ablak koordinátáit, a rajta lévő objektumok koordinátáit (pl. panel), de mit kell a régiónak ilyenkor megadni? A pl. panel koordinátáit vagy az egész windows asztal koordinátáiból az adott objektumra eső koordinátákat, vagy az adott form koordinátiból az adott objektum koordinátáit vagy esetleg csak az objektumét? (Utóbbi nem valószínű mert akkor nem lehetne egyedi formokat gyártani.)
Valamint nem értem hogy a GetWindowRgn-ből hogyan kapom meg a koordinátákat - mert sejtésem szerint nekem ez kell majd.

Senki. Csak kérdezem. Mivel azt gondoltam hogy a width, height annak a komponensnek a mérete amire kattintok. Viszont a leírás szerint először a régiót kell megadni. Csak akkor mit jelent a width és height? Minek a méretei? És miért van 5 CreateRectRgn? Ha ez 5 régió, akkor miért pont 5? Én úgy értettem, hogy kell 1 régió amin "mászkálok" - tehát a keret amiben rajzolni akarok - és egy amit bele akarok rajzolni. Több régiót lehet kombinálni és így érdekes alakzatokat létrehozni. Vagy nem így van?

Arra jutottam, hogy azt kell figyelnem a GetWindowRgn-vel, hogy van-e átfedés. Viszont ezt melyik értéke adja meg? Jól értem, hogy a régiók jobb alsó sarkának átfedését figyeli ez? De honnan tudja melyiket kell figyelje? A sorrendből? Mert hogy ha van egy nagy régióm és egy kicsi mozog rajta, akkor mindig azt fogja mondani hogy átfedés van. Én meg futás időben hozom létre a pl. gombokat. Honnan tudom meg a handle-jét a gombnak? Ill. Honnan tudom, hogy melyik régió melyik gombhoz tartozik? Azaz hogy éppen melyik gombot mozgatom a sok közül? (Pl. hogy melyik gombot tolom rá éppen a másikra, hiszen az álló gombot nem akarom eltolni.) És végül amit nem látok még ebből, hogy honnan tudom meg merre kell és hány pixelt mozgatni a gombot, hogy "leugorjon" a gombról? (Ha nem azt akarom hogy visszaugorjon a kiindulási pozícióba.)

Ja és még egy valami nem tiszta nekem: az angol leírásban az van, hogy ha befejeztem a régiók csesztetését, akkor meg kell szüntetnem őket. Ezek szerint ha a formot bezárom, vagy lecsukom akkor a régiókat is meg kell szüntetnem v. azt a windows automatikusan megteszi?

Tudom sok a kérdés, de még ilyet nem csináltam. előzmény
Ja és a színezés még mindig gond, mivel nem tudom miért csinálja, ráadásul a gomb tologatásakor a gomb eltűnik meg erősen villog.

Ezeket töröltem a kódból, de így is:

 BrActive := CreateSolidBrush( RGB( 255, 0, 0 ) );
  BrInactive := CreateSolidBrush( RGB( 200, 200, 200 ) );

  for i := 1 to pic_num - 1 do
    CombineRgn( Rgns[0], Rgns[0], Rgns[i], RGN_XOR );
end;
.
.
.
        // hoppsz, fedes van!
        FillRgn( Form1.Canvas.Handle, Rgns[i], BrActive )
      else
        FillRgn( Form1.Canvas.Handle, Rgns[i], BrInactive );

Miért színezi át?? előzmény

gomb tologatásakor a gomb eltűnik meg erősen villog.

DoubleBuffered!

előzmény
Nem attól van, anélkül sem vibrál ha nincs ez a régiós cucc. előzmény
Na ezt hoztam végül össze és gond nélkül megy:

OnMouseDown-ba:

var
i,a,b: integer;
LPanel: TPanel;
begin
  setlength(pontok, panel1.Width*panel1.Height);
  i:=0;
  while (i<panel1.Width*panel1.Height) do
  begin
  pontok[i]:=0;
  i:=i+1;
  end;

  i:=0;
  if Sender is TBitBtn then
  APanel := TBitBtn(Sender).Parent as TPanel
  else
  if Sender is TPanel then
  APanel := Sender as TPanel;

    while i <= Panel1.ComponentCount-1 do
    begin
      if (Panel1.Components[i] is Tpanel) then
      begin
      LPanel:=TPanel(Panel1.Controls[i]);
        if (LPanel.Name <> APanel.Name) then
        begin
        a:=(LPanel.Top-1)*Panel1.Width+LPanel.Left;
          while (a < (LPanel.Top+LPanel.Height-2)*Panel1.Width+LPanel.Left) do
          begin
          b:=0;
            while (b < LPanel.Width) do
            begin
            pontok[(a+b)]:=1;
            b:=b+1;
            end;
          a:=a+Panel1.Width;
          end;
        end;
      end;
    i:=i+1;
    end;
  end;

Az OnMouseUP-ba:

Var
i,a,b: integer;
APanel: TPanel;
begin
    if Sender is TBitBtn then APanel:=TBitBtn(Sender).Parent as TPanel
    else
    if Sender is TPanel then APanel:=Sender as TPanel;
    a:=((APanel.Top-1)*Panel1.Width)+(APanel.Left);
        while (a < (APanel.Top+APanel.Height-2)*Panel1.Width+APanel.Left) do
        begin
          b:=0;
          while (b < APanel.Width) do
          begin
            if (pontok[(a+b)] = 1) then
            begin
//ide jön amit csinálni akarok vele majd
            end;
          b:=b+1;
          end;
        a:=a+Panel1.Width;
        end;
    end;

Gyakorlatilag ezt csinálja meg a CreateRectRgn is. Csak itt nem rajzolgat, illetve ha azt akarom akkor én pontonként meg tudom mondani mit is rajzoljon.

Amire viszont még mindig nem jöttem rá, az az, hogy hogyan tudom olyan helyre tolni a közelben ahol van helye a komponensnek. Ehhez most már legalább van egy adathalmazom miben 0-val vannak jelölve azok a pontok amik szabadak. De hogyan tudom kitalálni hogy merre toljam?

Most azon gondolkozom, hogy nem az OnMouseUP-ba hanem az OnMouseMove-ba rakom és mindig eltárolom az előző csúcskoordinátát és ha átfedésbe kerül, akkor áttolom ebbe az előző koordinátába. Lehet ezzel valami gond? előzmény
Nos ez is megoldódott. :) Ahogy írtam úgy kell megoldani. Csak ott az onMouseDown-ra el kell tárolni a pozíciót majd azt kell csak figyelni hogy az OnMouseMove-ra belép-e olyan helyre ahol már van letárolva más komponens. És ha igen, akkor a top és left értékeit ezekkel a tárolt értékekkel feltölteni.

És nem árt arra is figyelni, hogy negatívba ne menjen át a pozíció mert az kivételt csinál és elszáll a progi (de a komponens is kezelhetetlenné válik, mivel eltűnik).

Mivel a feladatot végül is magam oldottam meg, így most a pont az enyém.

Viszont még nem pontozom magam, mert kíváncsi vagyok hogy hogyan lehetne ugyan ezt megoldani a régiós módszerrel. Így ha arra is befut egy jó megoldás, akkor a megoldóé a pont. előzmény
Oszd meg másokkal is!
Belépés
E-mail cím:
Jelszó:

cvonline.hu
»iOS fejlesztő
»Senior web programozó
»Java fejlesztő (Bécs)
»Java fejlesztő (front-end, backend)
»PHP fejlesztő (Ausztria, Németország)
»Solaris rendszermérnök
» még több állás
Kérdésed van?
Problémád, kérdésed van? Segítünk neked is. Csak kattints ide!
RSS források
-Hírek
-Cikkek
-Fórumok
-Állás/munka
Top pontgyűjtők
»Árnyék1.100
»silentworks910
»Robi80910
»szabofe860
»bubori.attila760
»djjjozsi680
»Galovics660
»Riha590
»Frostech0560
»Csaboka2550
A nap kifejezései
»Adatszegmens
»Konstans
»Makró
» ugrás a wikire
Hírek
»Az általános műveltség része kellene, hogy legyen a programozni tudás?
»Újra programozni fog a Facebook alapítója és multimilliárdos elnöke
»Vizuális felülettervezőt adott ki .NET-es Android-alkalmazásfejlesztéshez a Xamarin
» több hír
PC Fórum hírek
»Elvennék és felhasználóinak adnák a Facebook összes pénzét
»Rejtélyes ikont dugdosgat a Microsoft a Windows 8-ban
»Út a Windows 8-ig - a Windows rendszerek három évtizedének története, képekben
»Mától bárki regisztrálhat a so.cl-ra, a Microsoft közösségi oldalára
»Megérkeztek az első képek az Unreal Engine 4 játékmotorról
»Itt az első videó a a Firefox Windows 8-as változatáról
»Nyártól akár 150 megabites nethozzáférést is ad az Invitel
»Kilenc kritikus biztonsági hibát javít az új Google Chrome
Top wikieditorok
»Sting
»Doi
»FlamingClaw
»Argathron
»Csaboka2
»Muki987
»NevemTeve
»Ivn
»Kelemzol
»Joexy
» ugrás a wikire