Źle dopasowane elementy w oknie programu - Windows Vista i 7

0

Otóż mam taki problem. Piszę program, który jest swojego rodzaju edytorem. Chodzi o to, że w systemie Windows XP i starszych okno programu wygląda dobrze. Niestety w systemach Windows generacji 6, czyli Vista i 7 pojawia się taki problem:
user image
Po prostu ucina mi kilka pikseli z prawej strony. Napisałem nawet funkcję, która wykrywa rodzaj systemu operacyjnego i gdy wykryje Vistę lub 7-kę to program zmienia położenie przycisków troszkę w lewo i szerokość valuelisteditora. Niestety chciałem zaznaczyć, że po zmianie kompozycji na tą z Xp lub z 98 pozostaje mała szparka z prawej strony programu. Macie jakieś propozycje? Dodam tylko, że program ma na sztywno przypisany minimalny rozmiar okna i używam kompilatora Delphi 2007.

0

hmm... nie powinno tak byc, chyba ze zmieniasz cos dynamicznie.
jedyne co mi przychodzi do glowy to wziac pod uwage, ze width oznacza szerokosc okna razem z ramka.
wiec napisanie np:

button1.left:=width-button1.width;

bedzie sprawiac problemy.
jepiej uzywac ClientRect.Right - bo to zwroci Ci szerokosc wnetrza formy, przeznaczonego na umieszczanie komponentow.
mozliwe ze problem sprawia to przypisanie minimalnej szerokosci formy. pewnie tez ustawiana jest szerokosc formy razem z obramowaniem (ktore w przypadku visty jest szersze)...

0

No właśnie nic nie zmieniam dynamicznie. Sam się dziwię. ClientRect.Right nie zdaje egzaminu. Usunięcie minimalnego rozmiaru okna też nie rozwiązuje problemu. Macie jeszcze jakieś propozycje? Będę się starał coś jeszcze wykombinować.

P.S. Da się włączyć opcje disabled dla jednego elementu w combobox'ie? Chodzi mi o coś takiego: Combobox1.Items.Strings[1].Enabled := False;?

0

Chyba się w ComobBoxie standardowym nie da. Trzeba by było zrobić tak, że jak wybierzesz Item o Indeksie,
ktorego nie można wybrać to wtedy pokazuje się komunikat i ItemIndex ustawia się na -1 lub poprzedni Index.
Można to zrobić tak jak poniżej, ale tak się zastanawiam, jak zakładasz że jakiś Item nie jest do wybrania to w
takim razie po co go w ogóle pokazywać na ComboBoxie. Chyba, że chcesz zrobić Listę kategorii, ale to wtedy
bym używał do takich cełow TTreeView i operował na drzewku. Ewentualnie ListView i zdarzenia OnSelectItem.

procedure TForm1.ComboBox1Select(Sender: TObject);
begin
  if ComboBox1.ItemIndex = 1 then
  begin
    ShowMessage('Nie możesz wybrać tego elementu.');
    ComboBox1.ItemIndex := -1;
  end;
end;
0

mozna wykorzystac OwnerDraw i samemu narysowac "wygaszone" itemy:

ustaw OwnerDraw comboboxa na csOwnerDrawVariable lub csOwnerDrawFixed (nie pamietam czym to sie rozni...)

procedure TForm1.ComboBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
 with ComboBox1 do
      begin
       canvas.Font:=ComboBox1.Font;

       if index=3 then //wygaszamy 4 item
           begin
            Canvas.Brush.Color:=Color;
            canvas.font.Color:=clGray;
           end
       else
           if (odSelected in State) then
              begin
               Canvas.Brush.Color:=clHighlight;
               canvas.Font.Color:=clHighlightText;
              end
           else
              begin
               Canvas.Brush.Color:=Color;
               canvas.font.Color:=font.Color;
              end;

       canvas.FillRect(rect);
       Canvas.TextOut(rect.Left+2,rect.Top, Items[index]);
       if (index=3) and (odSelected in State)
          then canvas.DrawFocusRect(rect);
      end;
end;

procedure TForm1.ComboBox1DropDown(Sender: TObject);
begin
  //w momencie wyswietlenia listy zapamietujesz ktory item byl zaznaczony...
  ComboBox1.Tag:=ComboBox1.ItemIndex;
end;

procedure TForm1.ComboBox1Click(Sender: TObject);
begin
  //jezeli wybrano "wygaszony" element, wybieramy ten ktory byl ostatnio. czyli nic nie zostaje wybrane.
  if ComboBox1.ItemIndex=3
     then ComboBox1.ItemIndex:=ComboBox1.Tag;
end;
0
kalwiremi napisał(a)

Macie jeszcze jakieś propozycje?

spróbuj jeszcze tak

Button1.Anchors:=[akTop,akRight];
0

Dokładnie tak mam zrobione.

Słuchajcie mam jeszcze jedno małe pytanko.

Tu macie kod pliku *.dpr projektu:

program Edytor;

uses
  Windows, Forms, SysUtils,
  Unit1 in 'Unit1.pas' {Main},
  Unit2 in 'Unit2.pas' {O_programie},
  Unit4 in 'Unit4.pas' {Licencja},
  Unit3 in 'Unit3.pas' {Otwieranie},
  Unit5 in 'Unit5.pas' {Importowanie},
  Unit6 in 'Unit6.pas' {Edytuj_szukaj},
  Unit7 in 'Unit7.pas' {Tablica_znakow},
  Unit8 in 'Unit8.pas' {Pomoc},
  Unit9 in 'Unit9.pas' {Przebuduj_plik};

{$R *.res}
var
  localization: string;

begin
  Application.Initialize;
  localization := ExtractFilePath(Application.ExeName);
  if ((FileExists(localization + 'bin\core_4gta0975.gxc')) and (FileExists(localization + 'bin\core_4t10975.gxc')) and (FileExists(localization + 'bin\core_4t20975.gxc'))) then
    begin
      Application.Title := 'Edytor';
      Application.CreateForm(TMain, Main);
      Application.CreateForm(TO_programie, O_programie);
      Application.CreateForm(TLicencja, Licencja);
      Application.CreateForm(TOtwieranie, Otwieranie);
      Application.CreateForm(TImportowanie, Importowanie);
      Application.CreateForm(TEdytuj_szukaj, Edytuj_szukaj);
      Application.CreateForm(TTablica_znakow, Tablica_znakow);
      Application.CreateForm(TPomoc, Pomoc);
      Application.CreateForm(TPrzebuduj_plik, Przebuduj_plik);
      Application.Run;
    end
  else
    begin
      Application.MessageBox('Nie odnaleziono jednego ze składników aplikacji.  ', 'Edytor', MB_ICONERROR);
    end;
end.

Chciałem zrobić otwieranie plików przez 'Otwórz za pomocą...'. Cały rejestr mam zrobiony, ale chodzi mi o samą aplikację. Najprościej jest zrobić w zdarzeniu Main.FormCreate(); i jeśli parametry są różne od 0 i plik istnieje to wtedy otwiera plik, ale chodzi o to, że otwieranie musi wywoływać formę TOtwieranie, a nie jest ona jeszcze zainicjowana w momencie Main.FormCreate(); Nie mam pomysłu co z tym zrobić, a nie wiem czy możliwe jest wprowadzenie procedury takiego otwierania w pliku Edytor.dpr po linijce Application.Run;. Możecie mi coś doradzić?

0

A co za problem zmienić kolejność tworzenia formularzy? Zmień kolejność tworzenia:

...
Application.CreateForm(TOtwieranie, Otwieranie);
Application.CreateForm(TMain, Main);
...

//EDIT: A Jednak sie nie da bo zmienia się główny formularz ale pokombinuję jeszcze

No i znalazłem proste obejście tego że zmienia się Application.MainForm
Do pliku .dpr dodajesz procedurę

procedure SetAsMainForm(aForm:TForm);
var
  P:Pointer;
begin
  P := @Application.Mainform;
  Pointer(P^) := aForm;
end;

I podobnie jak poprzednio:

...
Application.CreateForm(TOtwieranie, Otwieranie);
Application.CreateForm(TMain, Main);
SetAsMainForm(Main);
...
Application.Run;
0

kalwiremi: jak chcesz zrobić otwieranie plików i to także przy otwartym już
programie to przenalizuj sobie kod projektu oraz modułu głownego, ktore
wrzuciłem pod poniższy adres. Może się to do czegoś także Tobie przyda.
http://www.speedyshare.com/files/22751293/multi_file_open.rar

0
kalwiremi napisał(a)
  Unit1 in 'Unit1.pas' {Main},
  Unit2 in 'Unit2.pas' {O_programie},
  Unit4 in 'Unit4.pas' {Licencja},
  Unit3 in 'Unit3.pas' {Otwieranie},

i ty się w tym „połapujesz”? ponazywaj unity sensownie, ja mam system taki że w module uMain.pas jest forma fMain itd.

0

Poradziłem sobie. Dzięki. Mam tylko jedno pytanie. Jak zrobię tak jak napisałeś z ustawianiem głównej formy, to gdy otwieram z parametru, to przy wyskoczeniu okienka 'Otwieranie' wyskakuje etykieta na pasku zadań, potem jak na tej formie otwieranie wybiorę otwórz, to ta etykieta na pasku zadań znika i po uruchomieniu formy 'Main' pojawia się jeszcze raz. Trochę denerwujące, masz jakiś sposób na ominięcie tego?

0

a nie prosciej zamiast sie tak babrac zamiast do onCreate dac np w onShow?

0

No więc tak. Podzieliłem wasze pomysły. Skorzystałem z procedury SetAsMainForm, a procedurę otwierania pliku wrzuciłem w Main.OnShow. Teraz śmiga ładnie. Mam do was chyba ostatnie pytanie odnośnie mojego programu. Gdy załaduje plik programem i fragmenty wyświetlają się w ValueListEditor, to po wykonaniu pewnej operacji następuje zmiana koloru tekstu w komórce za pomocą metody TCanvas. Tutaj macie fragment kodu:

Main.ValueListEditor1.Canvas.Font.Color := clBlue;
Main.ValueListEditor1.Canvas.Brush.Style := bsClear;
Main.ValueListEditor1.Canvas.FillRect(Rect);
pom := Main.ValueListEditor1.Cells[ACol, ARow];
Main.ValueListEditor1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, pom);

Chodzi o to, że jeśli wcześniej napis w komórce ValueListEditor'a bezpośrednio stykał się z suwakiem z prawej strony, to teraz zachodzi na niego o 1 piksel (napis jest o 1 piksel dłuższy). Macie propozycje pomocy? Bo ja osobiście nie jestem zbyt dobrze zorientowany w rysowaniu za pomocą TCanvas. Macie tutaj obrazek o co chodzi:

user image

0

mozesz zrobic tak:
zmierz jakiej szerokosci jest text: Canvas.TextWidth()
jesli jest szerszy niz szerokosc "Rect" to utnij go w odpowiednim miejscu i wypelnij np. kropkami.

  with ValueListEditor1.Canvas do
       begin
         s := Main.ValueListEditor1.Cells[ACol, ARow];
         if TextWidth(s)>=rect.right then
            begin
              while (TextWidth(s+'...')>=rect.right) and (s<>'') do
                 Delete(s, Length(s), 1);
              s:=s+'...';
            end;

         Font.Color := clBlue;
         Brush.Style := bsClear;
         FillRect(Rect);
         TextOut(rect.left+2, rect.top+2, s);
       end;
0

No niestety nie za bardzo to działa. Właściwie to jakby w ogóle to nie działało.

0

u mnie dziala.
chociaz czekaj.. mozliwe ze przez to "with..do.." nie bierze tego "rect" ktore powinno.

0

Niestety nie działa u mnie w żaden sposób. Ani z with... do, ani bez.

EDIT: Po prostu nie wyświetla tych kropek na końcu, nie skraca go, tylko wyświetla tak jak zawsze (wcześniej).

0

to napisz co konkretnie nie dziala albo sam debuguj.

0

Dobra poprawiłem, żeby działało i wygląda to tak (zmieniłem 'TextWidth(s) >= rect.right' na 'TextWidth(s) >= (rect.right - rect.left)'):

with ValueListEditor1.Canvas do
begin
  s := Main.ValueListEditor1.Cells[ACol, ARow];
  if TextWidth(s) >= (rect.right - rect.left) then
    begin
      while (TextWidth(s + '...')>=(rect.right - rect.left)) and (s<>'') do
        Delete(s, Length(s), 1);
      s:=s+'...';
    end;
  Font.Color := clBlue;
  //Brush.Style := bsClear;
  FillRect(Rect);
  TextOut(rect.left + 2, rect.top + 2, s);
end;

Tylko musiałem wyłączyć Brush.Style := bsClear;, gdyż pod kropkami było widać poprzednie czarne litery, no nie fajnie to wygląda, ale teraz Brush rysuje białe tło i ono i tak zachodzi na suwak więc i tak trochę lipa... A nie da się po prostu zmniejszyć szerokość Rect'a?

0

Jak na razie dałem sobie z tym spokój. Teraz mam takie pytanie, co byście poradzili w takiej sytuacji: W jakimkolwiek komponencie do edycji tekstu, chodzi mi głównie o Memo, RichEdit i Edit, gdy zaznaczę tekst, chciałbym zrobić, żeby po kliknięciu w zaznaczony tekst prawym przyciskiem myszy wyświetlało się przygotowane przeze mnie menu kontekstowe, a po kliknięciu lewym po prostu ustawiał się kursor normalnie w miejscu gdzie kliknąłem. Problemem jest jak dla mnie jak sprawdzić czy kliknięto w zaznaczony tekst, czy też nie. Z resztę raczej sobie poradzę. Mam jeszcze takie pytanko, czy mając zapisaną w zmiennej pozycje w tekście można sprawdzić czy dodano lub usunięto przed tą pozycją jakiś znak lub jeśli wklejono cały ciąg znaków lub usunięto to ile ich było?

0

chciałbym zrobić, żeby po kliknięciu w zaznaczony tekst prawym przyciskiem myszy wyświetlało się przygotowane przeze mnie menu kontekstowe, a po kliknięciu lewym po prostu ustawiał się kursor normalnie w miejscu gdzie kliknąłem.

podpinasz do memo popupMenu a potem w kodzie dla zdarzenia OnClick dla wybranej przez Ciebie pozycji w menu dajesz taki kod:

ShowMessage(
copy(memo1.text,Memo1.SelStart,Memo1.SelLength)
);

w tym przypadku bedziesz miał message z zaznaczonym tekstem.

czy mając zapisaną w zmiennej pozycje w tekście można sprawdzić czy dodano lub usunięto przed tą pozycją jakiś znak lub jeśli wklejono cały ciąg znaków lub usunięto to ile ich było?

Wszystko można :) Mogłeś też założyć nowy temat zamiast ten odświeżać.

1 użytkowników online, w tym zalogowanych: 0, gości: 1