Temat: Pytanie do specjalistów od WinForm

Jak w temacie, pytanie do specjalistów:

czy istnieje możliwość przysłonięcia (wysłania) do utworzonego obiektu klasy Form metody CreateParams, która będzie zawierała zmodyfikowaną wersję, której zadaniem byłaby modyfikacja wyglądu formy (konkretnie na moim przykładzie usunięcie belki tytułowej okna, ale pozostawienie możliwości zmiany rozmiaru okna przez użytkownika). Z takim przysłonięciem metody CreateParams nie mam problemu w przypadku powołania nowego obiektu MojejFormy, która dziedziczy po Form. Problem jednak w tym, że ja orzymuję już obiekt Formy, który muszę przekształcić.

Jakieś propozycje?
Przemysław Krygier

Przemysław Krygier Specjalista Systemów
Informatycznych

Temat: Pytanie do specjalistów od WinForm

Witam
Kiepsko to wygląda ... w debugerze najpierw jest odwołanie do właściwości CreateParam ... a później dopiero do konstruktora:
wnioskuję że jest to tak głęboko zakopane w API windows, że się nie uda ...

Będę się przyglądał tej dyskusji :)

Pozdrawiam
Rafał Kiełbus

Rafał Kiełbus #blockchain
developer, #bitcoin
maximalist,
#ethereum mage

Temat: Pytanie do specjalistów od WinForm

Uściślij:
- masz już stworzony/wyświetlony obiekt Form?
- modyfikacja ma nastąpić przez wywołanie z innego Forma?
- modyfikacja ma polegać tylko na usunięciu belki?
- czy koniecznie chcesz/musisz wykorzystać CreateParams?

Temat: Pytanie do specjalistów od WinForm

A więc uściślam:

- mam już utworzony, ale nie wyświetlony obiekt, a dokładniej coś w stylu:

Form frm = new Form();

- modyfikacja ma nastąpić z innej formy
- generalnie chodzi mi o usunięcie belki, ale! pozostawienie możliwości zmiany rozmiaru okna (musi pozostać również tytuł na pasku zadań)
- nie muszę wykorzystywać CreateParams, mogę to zrobić inaczej, tylko nie wiem jak? część właściwości formy podmieniam w trakcie zdarzenia Shown, jednak w ten sposób usunąć belki się nie da... da się poprzez zmianę FormBorderStyle na None, ale tracę również możliwość zmiany rozmiaru okna, można również wyłączyć ControlBox oraz usunąć tytuł okna - wtedy otrzymuję
to czego potrzebuję, wadą jest jednak, że tracę również tytuł na pasku zadań, a to jest niedopuszczalne.

Przez głowę przeleciał mi również pomysł, aby ustawić FormBorderStyle na None, a także dynamicznie potworzyć różne panele z odpowiednimi Dockami i spróbować podmienić zdarzenia MouseDown oraz MouseMove, aby reagowały w sposób umożliwiający zmianę rozmiaru okna, ale jest to rozwiązanie bardzo toporne, zresztą z licznymi wadami...Rafał T. edytował(a) ten post dnia 26.12.09 o godzinie 16:24
Łukasz S.

Łukasz S. .NET developer, Łódź

Temat: Pytanie do specjalistów od WinForm

Witaj,

coś co mi przychodzi na szybko - ale podobnie jak z tymi zdarzeniami myszy - lekko toporne:

- ustawienie nowego regionu dla Formy.
- daje możliwość przycięcia góry
- wadą jest to, że należałoby aktualizować ten region przy każdym resizowaniu formy....

Fragmenty kodu:

frm.ResizeEnd += new EventHandler(frm_ResizeEnd);
UpdateFormBounds(frm, 30);


void frm_ResizeEnd(object sender, EventArgs e)
{
Form senderForm = sender as Form;
if (sender != null)
{
UpdateFormBounds(senderForm, 30);
}
}


private void UpdateFormBounds(Form frm, int y_offset)
{
frm.Region = new Region(new Rectangle(0, y_offset, frm.Width, frm.Height - y_offset));
}


PozdrawiamŁukasz Stebelski edytował(a) ten post dnia 26.12.09 o godzinie 18:01
Jacek Salamon

Jacek Salamon Programista

Temat: Pytanie do specjalistów od WinForm

A może mógłbyś dynamicznie tworzyć nową formę klasy MojaForma i kopiować do niej wszystkie kontrolki otrzymanego obiektu Form?

A w Twojej formie najlepiej jest ustawić FormBorderStyle na None i przeładować WndProc:


private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
private const int HTBOTTOM = 15;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int WM_NCHITTEST = 0x84;

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCHITTEST)
{
Point pt = new Point(m.LParam.ToInt32());

pt = this.PointToClient(pt);
if (pt.Y < 4 && pt.X < 4) m.Result = new IntPtr(HTTOPLEFT);
else if (pt.Y < 4 && pt.X > (this.Width - 4)) m.Result = new IntPtr(HTTOPRIGHT);
else if (pt.Y < 2) m.Result = new IntPtr(HTTOP);
else if (pt.Y > (this.Height - 4) && pt.X < 4) m.Result = new IntPtr(HTBOTTOMLEFT);
else if (pt.Y > (this.Height - 4) && pt.X > (this.Width - 4)) m.Result = new IntPtr(HTBOTTOMRIGHT);
else if (pt.Y > (this.Height - 2)) m.Result = new IntPtr(HTBOTTOM);
else if (pt.X > (this.Width - 2)) m.Result = new IntPtr(HTRIGHT);
else if (pt.X < 2) m.Result = new IntPtr(HTLEFT);
else base.WndProc(ref m);
}
else base.WndProc(ref m);
}

Temat: Pytanie do specjalistów od WinForm

@Łukasz:
Pomysł ciekawy jednak tracę możliwość zmiany rozmiaru okna od górnej krawędzi (poza tym trzeba "ręcznie" ją dorysować), a samo resizowanie też dziwnie się zachowuje.

@Jacek:
Wątek dotyczący dynamicznego przepisywania metod już się toczy tutaj.

Co do przeładowania metody to oczywiście, ale powiedz jak to zrobić w momencie, gdy mam już powołany obiekt?
Jacek Salamon

Jacek Salamon Programista

Temat: Pytanie do specjalistów od WinForm

Co do przeładowania metody to oczywiście, ale powiedz jak to zrobić w momencie, gdy mam już powołany obiekt?

Jak masz już powołany, to nie przeładujesz, ale możesz skopiować wszystkie właściwości i kontrolki otrzymanej formy do nowej formy Twojej klasy i wyświetlić Twoją zamiast tej otrzymanej. W C++ to się nazywało konstruktor kopiujący.
Rafał Kiełbus

Rafał Kiełbus #blockchain
developer, #bitcoin
maximalist,
#ethereum mage

Temat: Pytanie do specjalistów od WinForm

frm.FormBorderStyle=FormBorderStyle.None;
znika pasek, ale musisz dopisać przenoszenie forma i zmianę rozmiaru (OnMouseDown/Up/Move kontrola położenia myszy względem wielkości formy i albo this.location przy przenoszeniu albo this.ClientSize przy zmianie rozmiaru).
Żeby było można z innej formy to musisz "tylko" dać Public w konstruktorze, chyba że podaną komenda sam tworzysz ten form i wyświetlasz - wtedy tylko borderstyle przed show().

Temat: Pytanie do specjalistów od WinForm

@Rafał:
Tak, wiem. Wykonałem już coś takiego, ale rozwiązanie jest bardzo toporne. Abym mógł cokolwiek resizować muszę najpierw utworzyć regiony na formie (robię to za pomocą Paneli), które mają przypisane odpowiednie zdarzenia myszy. Paneli wychodzi w sumie 8 (góra, dół, lewy, prawy, a także 4 w narożnikach). Wada takiego rozwiązania to przede wszystkim te nieszczęsne regiony, które psują wygląd formy (najpiej widać to po umieszczeniu StatusStripa, który nie rozciąga się na całą szerokość). Poza tym, aby można było w miare wygodnie rozciągać formę, należy ustawić gruboć panelu przynajmniej na 3 piksele, a więc wygląda to troche dziwnie.

@Jacek:
A podałbyś mały przykład?

konto usunięte

Temat: Pytanie do specjalistów od WinForm

Rafał T.:
@Rafał:
Tak, wiem. Wykonałem już coś takiego, ale rozwiązanie jest bardzo toporne. Abym mógł cokolwiek resizować muszę najpierw utworzyć regiony na formie (robię to za pomocą Paneli), które mają przypisane odpowiednie zdarzenia myszy.

możesz wszystko osadzić na TableLayoutPanel ewenetualnie zagnieździć kilka w Sobie i odpowiednio po ustawiać. Następnie włożyć elementy do środka i ustawić odpowiednio anchoring :)

Oczywiście ten główny Panel dajesz Dock Fill.
Na elementach w środku ( innych kontrolkach ) ustawiasz tylko Anchor, Dock masz na None.

Skalowanie działa wyśmienicie wtedy.Łukasz Machowski edytował(a) ten post dnia 30.12.09 o godzinie 11:47
Jacek Salamon

Jacek Salamon Programista

Temat: Pytanie do specjalistów od WinForm

Rafał T.:
@Jacek:
A podałbyś mały przykład?

A proszę bardzo:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;

namespace WindowsFormsApplication1
{
public partial class MojaForma : Form
{
public MojaForma()
{
InitializeComponent();
this.Text = "Forma główna";
Form stara = new Form();
stara.Text = "Stara forma";
Button b = new Button();
Button b2 = new Button();
b.Text = "XXX";
b2.Text = "YYY";
b2.Location = new Point(0, 30);
stara.Controls.Add(b);
stara.Controls.Add(b2);
MojaForma nowa = new MojaForma(stara);
nowa.Text = "Nowa forma";
nowa.Show();
}
public MojaForma(Form forma) //Konstruktor kopiujący
{
InitializeComponent();
//Kopiowanie kontrolek:
while (forma.Controls.Count > 0)
{
Control c = forma.Controls[0];
forma.Controls.Remove(c);
this.Controls.Add(c);
}
//Kopiowanie właściwości:
Type typFormyKopiowanej = forma.GetType();
PropertyInfo[] wlasciwosciFormyKopiowanej = typFormyKopiowanej.GetProperties();
int i = 0;
foreach (PropertyInfo p in wlasciwosciFormyKopiowanej)
{
if (p.GetSetMethod(false) == null) continue; //nie interesują nas właściwości, które
//nie mogą być ustawione
if (p.GetGetMethod(false) == null) continue;
if (p.Name == "Visible") continue; //ta właściwość nas nie interesuje
//MessageBox.Show(p.Name);
object wartosc = p.GetValue(forma, null);
p.SetValue(this, wartosc, null);
if (i > 50) break; //Skopiowanie którejś tam z kolei właściwości powoduje problemy
//z rysowaniem formy, więc kopiuję tylko pierwsze 50. Nie chce mi się
//dociekać która to właściwość. Wogóle to coś dziwnego, bo coś podejrzanie
//dużo tych właściwości
i++;
}
//I usunięcie ramek:
this.FormBorderStyle = FormBorderStyle.None;
this.TopMost = true; //żeby główna forma jej nie przesłoniła - tylko dla testów
}

//No i teraz owerrajdowanie WuendeProca
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
private const int HTBOTTOM = 15;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int WM_NCHITTEST = 0x84;

protected override void WndProc(ref Message m)
{
if (m.Msg == WM_NCHITTEST)
{
Point pt = new Point(m.LParam.ToInt32());

pt = this.PointToClient(pt);
if (pt.Y < 4 && pt.X < 4) m.Result = new IntPtr(HTTOPLEFT);
else if (pt.Y < 4 && pt.X > (this.Width - 4)) m.Result = new IntPtr(HTTOPRIGHT);
else if (pt.Y < 2) m.Result = new IntPtr(HTTOP);
else if (pt.Y > (this.Height - 4) && pt.X < 4) m.Result = new IntPtr(HTBOTTOMLEFT);
else if (pt.Y > (this.Height - 4) && pt.X > (this.Width - 4)) m.Result = new IntPtr(HTBOTTOMRIGHT);
else if (pt.Y > (this.Height - 2)) m.Result = new IntPtr(HTBOTTOM);
else if (pt.X > (this.Width - 2)) m.Result = new IntPtr(HTRIGHT);
else if (pt.X < 2) m.Result = new IntPtr(HTLEFT);
else base.WndProc(ref m);
}
else base.WndProc(ref m);
}

}
}


W konstruktorze klasy MojaForma tworzone są dwie nowe formy: forma klasy Form i druga forma klasy MojaForma, która przejmuje kontrolki i właściwości starej formy klasy Form dzięki konstruktorowi kopiującemu. Nowa forma jest wyświetlana, a stara nie.Jacek Salamon edytował(a) ten post dnia 02.01.10 o godzinie 15:25

Następna dyskusja:

pytanie do programistów




Wyślij zaproszenie do