Diskuze: ListView Edit Design
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.


David Jančík:19.1.2013 19:48
Dej tam normálně tiles a dej si vlastní kreslení položek jak to mám taj: http://www.itnetwork.cz/…list-a-mutex
matesax:19.1.2013 19:57
Chtěl jsem mu poradit, ať si to zdědí, ale ObjectListView splňuje všechny jeho požadavky...
Зайчик:19.1.2013 21:21
ještě k tomu mám dotaz udělal jsem si to takhle :
foreach (int SelectedIndex in this.ServerList.SelectedIndices)
{
if (e.ItemIndex == SelectedIndex)
{
// border
e.Graphics.FillRectangle(Brushes.Black, e.Bounds.X, e.Bounds.Y, BorderWidth, e.Bounds.Height - 1);
e.Graphics.DrawRectangle(new Pen(Brushes.White), e.Bounds.X, e.Bounds.Y, BorderWidth - 1, e.Bounds.Height - 1);
}
else
{
// border
//e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.X, e.Bounds.Y, BorderWidth, e.Bounds.Height - 1);
//e.Graphics.DrawRectangle(new Pen(Brushes.Transparent), e.Bounds.X, e.Bounds.Y, BorderWidth - 1, e.Bounds.Height - 1);
}
e.Graphics.DrawString(e.Item.Text, font, SelectedTextColor, e.Bounds.Left, e.Bounds.Top + 1);
}
Ale když vlastně překliknu na jinej item tak se mi vlastně else nic
neudělá no.. viz obrázky
jeden je ok... a ty dva jsou docela zrůdovina
nevíš kde mám chybu?
Зайчик:19.1.2013 21:38
ještě jsem to zkusil takhle ale tu se mi vyplní if i else ale je to to
samé jako na obrázkách akorát místo transparentu je bíla
if (e.Item.Selected == true)
{
// border
e.Graphics.FillRectangle(Brushes.Black, e.Bounds.X, e.Bounds.Y, BorderWidth, e.Bounds.Height - 1);
e.Graphics.DrawRectangle(new Pen(Brushes.Black), e.Bounds.X, e.Bounds.Y, BorderWidth - 1, e.Bounds.Height - 1);
}
else if (e.Item.Selected == false)
{
e.Graphics.FillRectangle(Brushes.White, e.Bounds.X, e.Bounds.Y, BorderWidth, e.Bounds.Height - 1);
e.Graphics.DrawRectangle(new Pen(Brushes.White), e.Bounds.X, e.Bounds.Y, BorderWidth - 1, e.Bounds.Height - 1);
}
e.Graphics.DrawString(e.Item.Text, font, SelectedTextColor, e.Bounds.Left, e.Bounds.Top + 1);
ok tak jsem to vyřešil
private void ServerList_DrawItem(object sender, DrawListViewItemEventArgs e)
{
if (e.ItemIndex == -1) return;
Graphics g = e.Graphics;
using (Brush textBrush = new SolidBrush(Color.White))
{
Brush TextColor = Brushes.Black;
Brush SelectedTextColor = Brushes.Blue;
// border
if (e.Item.Selected == true)
{
// Draw the new background color
e.DrawBackground();
e.Graphics.FillRectangle(Brushes.Black, e.Bounds.X, e.Bounds.Y, e.Bounds.Width + 200, e.Bounds.Height - 1);
}
else
{
e.DrawBackground();
e.Graphics.FillRectangle(Brushes.Transparent, e.Bounds.X, e.Bounds.Y, e.Bounds.Width + 200, e.Bounds.Height - 1);
}
Font font = ServerList.Font;
Color colour = ServerList.ForeColor;
e.DrawText();
Bitmap MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.on;
e.Graphics.DrawImage(MyIcon, e.Bounds.Left + 190, e.Bounds.Top + 8, 10, 10);
MyIcon.Dispose();
}
}
Зайчик:23.1.2013 18:44
Hoj, mám takový problém opět s listviewem. Aplikace funguje tak, že pokud už nějaký item v listviewu existuje tak to označí první item v listviewu. No a pokud tam není tak se samozřejmě nic neděje. Problém je že jde kliknout kamkoli jinam v listviewu i mimo itemy což je špatně, protože pak není označený žádný item a to nechci. Potřebuju aby vždy byl označen item pokud tam nějaký je. Zkoušel jsem to různě přes eventy click a mouse click ale zatím neúspěšně... popřípadě věděl bys jak udělat aby to bralo jako item celý řádek, ne jen text? Představoval jsem si to nějak řešit přes
e.Bounds.X && e.Bounds.Y
V drawitemu ale to je asi pěkná kravina. Předem dík za každou nápovědu.
David Jančík:23.1.2013 21:07
Si ulož poslední označený item. A pak se orientuj podle něj.
Зайчик:23.1.2013 21:20
To jsi mi toho moc neřekl teda. Vůbec nevím v čem mi pomůže, že budu znát poslední selected item. Protože ani nevím, kam to psát já osobně si myslím že to bude fajn buď do drawitem (ale tu mi na to pořád reaguje i hover myši) nebo do listview.itemindexchanged eventu, ale vůbec nevím jak zjistit že jsem vlastně kliknul mimo ( to je to hlavní co bych potřeboval vědět). Nejde nějak úplně vypnout to kliknutí na background listviewu? Že by to šlo jen na itemy?
David Jančík:23.1.2013 21:29
Já myslel, že ti jenom vadí, když není označený nějaký item a chceš provést akci. To sme si dycky ukládal index označeného prvku. Pokud chceš, abys dycky kliknul někam a ikdyž to bude mimo tak se ti označil prvek. Já si třeba taby projedu a kontroluju kam kliknul:
Point p = this.chatTabs.PointToClient(Cursor.Position);
for (int i = 0; i < this.chatTabs.TabCount; i++)
{
Rectangle r = this.chatTabs.GetTabRect(i);
if (r.Contains(p))
{
Tak když si tady upravíš velikost toho obdélníčku tak víš index prvku a ten pak vybereš SelectedItem = item[i];
Зайчик:23.1.2013 22:22
No prozatím mi vadí jen to že se může stát že žádný item není
zaškrtnutý to já si uložím index nějakého selected itemu
int posledni;
posledni = ServerList.SelectedItems[0].Index;
no a mam poslední selected item když to prdnu třeba do ServerList_SelectedIndexChanged metody ale pokud kliknu někde vedle tak se index nezmění a hodnotu tak z toho nedostanu žádnou... jsem si to představoval nějak takto :
if(ServerList.SelectedItems[e.ItemIndex] == true)
// nějakej server při vykreslování je
else
// není žádnej
no ale pořád ať se snažím jak se snažím tu hodnotu když už není
žádný selected prostě nemůžu dostat
David Jančík:24.1.2013 6:27
Tak tam by mělo stačit. If selectedItems.Count > 0
a při
změně indexu stačí ukládat selectedIndex
pokud není vybraný
bude -1.
if (ServerList.SelectedItems.Count > 0)
Když použíju tuhle podmínku, tak se mi provede vždy, když překliknu na
jiný item. Takže je to celkem na nic vždy jak překliknu tak ten selected
item je -1
achjo to je bordel xD
David Jančík:24.1.2013 8:58
Můžeš sem hodit kus zdrojáku, abych z toho líp pochopil co přesně tam potřebuješ?
Зайчик:24.1.2013 11:04
no heleť já ani nevím kam to šoupnout ale draw item:
private void ServerList_DrawItem(object sender, DrawListViewItemEventArgs e)
{
Bitmap MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.off;
if (e.Item.Selected == true)
{
ServerList.ForeColor = Color.FromArgb(50, 146, 242); // blue text color
SolidBrush ItemColor = new SolidBrush(Color.FromArgb(51, 51, 51)); // gray ( 51, 51, 51) background color
Color BorderColor = Color.FromArgb(51, 102, 153); // blue ( 51, 102, 153 ) border color
e.Graphics.FillRectangle(ItemColor, e.Bounds.X, e.Bounds.Y, (float)210, e.Bounds.Height - 1); // active border
e.Graphics.DrawRectangle(new Pen(BorderColor), e.Bounds.X, e.Bounds.Y, (float)209, e.Bounds.Height - 1); // normal border
e.DrawText();
}
else
{
e.DrawText();
}
fl.LoadMyFile(ServersDir + e.Item.Text + Suffix, out Help[4]);
string[] q = Help[4].Split(';');
object[] info = { e.Item.Text, q[1], e.ItemIndex };
Thread th = new Thread(TcpTest);
th.Start(info);
if (Connection[e.ItemIndex] == "test")
{
MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.off;
}
else
{
MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.on;
}
e.Graphics.DrawImage(MyIcon, e.Bounds.Left + 180, e.Bounds.Top + 8, 10, 10);
}
a
private void ServerList_SelectedIndexChanged_1(object sender, EventArgs e)
{
if(ServerList.SelectedItems.Count >= 0)
MessageBox.Show("ahoj");
ServerList.Invalidate();
try
{
fl.LoadMyFile(ServersDir + ServerList.SelectedItems[0].Text + Suffix, out Help[5]);
}
catch
{
// nothing so far
}
string[] s = Help[5].Split(';');
realm.Text = s[1];
site.Text = s[3];
type.Text = s[2];
mss.Text = MS[ServerList.SelectedItems[0].Index] + " Ms";
if (MS[ServerList.SelectedItems[0].Index] == "0")
{
Status.ForeColor = Color.FromArgb(51, 51, 51);
Status.Text = "Offline";
}
else
{
Status.ForeColor = Color.FromArgb(50, 146, 242);
Status.Text = "Online";
}
}
a nevím co, kam, jak.
David Jančík:24.1.2013 14:39
Ej ty to máš upe nakombený, já vůbec nevim co mám na to napsat
Když si dáš při vykonávání akce podmínku
if (SelectedItems.Count > 0)
tak bys neměl mít problém ne?
Ale z toho co jsi psal jsem pochopil, že chceš furt mít nějakej vybranej.
Tak si v SelectedItemIndexChanged
ulož e.Index
do
nějaké proměnné (pokud není -1) a pak se v té akci prostě odkážeš na
poslední známí označený item.
Зайчик:24.1.2013 15:08
ale když
private void ServerList_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
{
AppTitle.Text = e.Item.Index.ToString();
}
Do AppTitle.Text se zapisuje jen pokud změním na další selected item
vypisuje to 1,2,3,4 ale když kliknu vedle zůstane tam ten poslední zápis ale
že by někde bylo -1 to ne:S ty pořád děláš jako kdybych neuměl udělat
podmínku já jen nevím,
jak zjistit že už jsem mimo
protože kde nic tu nic
Kit:24.1.2013 15:19
A nepolykáš tam někde výjimku? Proč by se tam mělo objevovat "-1", pokud to není platná hodnota?
David Jančík:24.1.2013 16:06
Né, to né, já jsem nějak mimo, páč do teď nevim, co po mě chceš
Dycky něco napíšu a ty uděláš něco jinýho a řekneš, že to nejde
Takhle jsem to myslel: https://dl.dropbox.com/…ViewTest.zip
S tím, že si můžeš zvolit výchozí hodnotu (výchozí vybraný prvek), takže vždycky se některý vybere.
Зайчик:24.1.2013 16:27
hehe tak ještě jednou. Já potřebuju aby vždy alespoň jeden item byl
"selected" aby se nemohlo stát že žádný item není označený... aby vždy
byl označený aspoň jeden je jedno jaký z nich ale aby vždy kolem nějakého
itemu byl ten šedý rámeček viz obrázky... ale když kliknu nějak do
listviewu mimo text ( itemů ) tak není selected žádnej ( kolem žádného
itemu není ten šedý rámeček ) a toho se právě potřebuju zbavit
David Jančík:24.1.2013 16:35
Jo takhle. Tak nejjednodušší bude při vykreslování změnit
podmínku:
if (e.Item.Selected == true)
na
if (e.Item.Index == lastIndex)
To se neprovede nikdy pokud bude lastIndex -1 takže to ošetřovat nemusíš a navíc si nastavíš výchozí hodnotu lastIndex = 0 aby vždy se vybral první prvek a od začátku již byl vybraný takže tam -1 nebude nikdy.
Зайчик:24.1.2013 17:02
no hurááááá díky
mnohokrát :[ ještě jednu věc bych se chtěl zeptat drawitem mam teď takto
:
Bitmap MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.off; // tady mám základní obrázek off šedý
if (e.Item.Index == lastIndex)
{
// tady je vykreslování textu, rámečku a takovejch blbostí
ServerList.ForeColor = Color.FromArgb(50, 146, 242);
SolidBrush ItemColor = new SolidBrush(Color.FromArgb(51, 51, 51));
Color BorderColor = Color.FromArgb(51, 102, 153);
e.Graphics.FillRectangle(ItemColor, e.Bounds.X, e.Bounds.Y, (float)210, e.Bounds.Height - 1);
e.Graphics.DrawRectangle(new Pen(BorderColor), e.Bounds.X, e.Bounds.Y, (float)209, e.Bounds.Height - 1);
e.DrawText();
}
else
{
e.DrawText();
}
// tady se načte soubor pro zjištění ip, který se bude pingovat šlo by to i bez souboru xD
fl.LoadMyFile(ServersDir + e.Item.Text + Suffix, out Help[4]);
// tady si to rozdělím a získám tu ip
string[] q = Help[4].Split(';');
// do objektu uložím název serveru, ip, a index
object[] info = { e.Item.Text, q[1], e.ItemIndex };
// vytvořím nové vlákno kde se testuje ta ip adresa jestli je online/offline
Thread th = new Thread(TcpTest);
th.Start(info);
// v té funkci která zjištuje jestli je server offline nebo online
// se hodnota uloží do listu buď "test" (offline) nebo MS(online)
// když tam bude test tak obrázek bude šedý
if (Connection[e.ItemIndex] == "test")
{
MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.off;
}
// jinak bude modrý (online)
else
{
MyIcon = global::Soulwell___Realmlist_modifer.Properties.Resources.on;
}
// vykreslí obrázek
e.Graphics.DrawImage(MyIcon, e.Bounds.Left + 180, e.Bounds.Top + 8, 10, 10);
}
Ale mám tu takový problémek ( nic vážného ) ale pak to nevypadá tak
dobře, jak by mělo. Když se zapne aplikace tak jsou všechny servery offline
(šedé kolečko) i když už se refreshujou... drawitem pořád nic nezobrazí
pokud nekliknu na nějaký item prostě je nutný kliknout na nějaký item aby
se změnili obrázky... věděl bys jak to udělat aby se změnili i bez toho
abych musel klikat na na listview na nějaký item? Promiň že se pořád ptám
ale ty dvě věci, na které se teď ptám dělám asi 2dny a zaboha na to nemůžu přijít
tohle je poslední věc,
která mi chybí pro dokončení
David Jančík:24.1.2013 17:19
Měl by jít listView1.Refresh();
A teď koukám, že pokud nechceš aby ti to blikalo tak je tam
RedrawItems
a tam si dáš pložky, které se mají
překreslit.
Зайчик:26.1.2013 13:27
Ahoj, tak aplikace je v takové fázi testování a zjistili jsme asi 20 bugů. No všechny jsou fixnutý až na jeden... docela zásadní. Pokud přidám item, který je moc dlouhý tak se to vlastně dostane za ten můj obrázek celý je to hnusný potom. Tak jsem to zkoušel rovnou v přidávání itemů alias při zadávání názvu serveru se mění délka ale... ale byly tam nějaký problémy s velkými písmeny a podobně. Pak mě napadlo udělat to přímo v drawitemu. Udělal jsem si takovou podmínku...
if (e.Bounds.Right > 175)
e.Graphics.DrawString("...", e.Item.Font, ForeText, e.Bounds.Left + 2, e.Bounds.Top + 1);
else
e.Graphics.DrawString(e.Item.Text, e.Item.Font, ForeText, e.Bounds.Left + 2, e.Bounds.Top + 1);
to znamená že pokud text přesahuje 175 pixelů tak se změní na "...".
Tak a tu je ten problém. Jednak že dolní scroll bar se stejně objeví i
když tam už není ten velký text což bude tím že v listboxu je pořád ten
velký text akorát ho sám vykresluju. A chtěl bych aby výsledek byl prostě
"WWWWWWWWWWWWW" a na konci když bude text delší tak se text uřízne a na
konci bude "WWWWWWWWWWWW..." Snad jsem to vysvětlil dobře budu rád za každou radu ale
opravdu nevím jak na to
doufal
jsem že to půjde nějak v listboxu automaticky
předem díky
David Jančík:26.1.2013 13:40
Dal bych na délku "m" kolik se jich tam vejde a pak jen:
public static string SortText(this string text, int length)
{
if (text.Length > length + 3)
return text.Substring(0, length) + "...";
return text;
}
Jinak na získání velikosti textu v pixelech je tam fce:
MeasureString
lze použít při kreslení Graphics
Зайчик:26.1.2013 14:07
Ale já to právě že nemůžu udělat na délku písmenek protože třeba W je delší než A a podobně takže když tam bude velký písmeno tak dáme délku 17 písmen aby to vyšlo ale když tam bude W 17x tak se to za to stejně dostane.
David Jančík:26.1.2013 14:09
Právě proto říkám ať to děláš podle "m" to je tuším nejdelší
písmeno. Nebo použij to MeasureString
. Ty mi dycky všecko
zkritizuješ dřív než to zkusíš nebo nad tím popřemejšlíš
Зайчик:26.1.2013 14:51
jo promiň, já už jsem z toho na prášky zkusil jsem to takhle:
SizeF ms = e.Graphics.MeasureString("MMMMM", e.Item.Font);
if (e.Item.Text.Length > ms.Width + 3)
e.Item.Text = e.Item.Text.Substring(0, (int)ms.Width) + "...";
e.Graphics.DrawString(e.Item.Text, e.Item.Font, ForeText, e.Bounds.Left + 2, e.Bounds.Top + 1);
Jestli jsem to dobře pochopil, což asi ne protože to nic nedělá nejspíš to ani nevleze do ty podmínky xD
David Jančík:26.1.2013 14:58
Tak ještě jednou
- Písmeno "m" má nejdelší délku. Takže si dej item s mkama a pdoívej se kolik se jich tam vejde. Pak použiješ substring a zkrátíš text pokud bude obsahovat více písmen než je maximální počet písmen m které ve vlezou do řádku, aby nepřetékal.
- Použiješ
MeasureString
to ti vrátí délku v pixelech daného slova pro daný font. To bys pak podmínkoval podle velikosti položky.
Зайчик:26.1.2013 15:12
- hodil jsem si item jen s mkama ( vejde se jich tam 12 maximum )
- Pak jsem zjistil pomoci MeasureString délku slova
SizeF ms = e.Graphics.MeasureString(e.Item.Text, e.Item.Font);
3. vytvořil podmínku pokud je délka slova větší než 12 ( maximální počet Mek ) změním počet písmen na 12
if (ms.Width > 12)
e.Item.Text = e.Item.Text.Substring(0, 12);
a vykreslím text
e.Graphics.DrawString(e.Item.Text, e.Item.Font, ForeText, e.Bounds.Left + 2, e.Bounds.Top + 1);
a celkově :
SizeF ms = e.Graphics.MeasureString(e.Item.Text, e.Item.Font);
if (ms.Width > 12)
e.Item.Text = e.Item.Text.Substring(0, 12);
e.Graphics.DrawString(e.Item.Text, e.Item.Font, ForeText, e.Bounds.Left + 2, e.Bounds.Top + 1);
Bylo mi řečeno že "Index a délka musí odkazovat na umístění v rámci
řetězce
Název parametru : length"
ale e.Item.Text.Length změnit nemůžu protože "read only"
David Jančík:26.1.2013 15:16
Tak to je snad jasný ne?
Hele udělej to prostě jak sem ti už řekl 3x:
if (text.Length > 12)
text = text.ShortText(12);
Ta fce je cool, že se podívá, jestli se na místo teček nevejde zbytek slova. A vůbec nci nepoměřuj, děláš mooooc komba.
Зайчик:26.1.2013 15:35
ty jsi mě strašně spletl tím "MeasureString"
if (e.Item.Text.Length > 14)
e.Item.Text = e.Item.Text.Substring(0, 14);
Takhle to funguje teď
tam mam ještě jednu zradu, kterou jsem způsobil tímhle
ale s tím už si vím rady
díky
Зайчик:4.2.2013 0:12
Hoj, měl bych ještě dotaz k tomu označení itemu aby mi vlastně fungoval
celý řádek jako item a né jen text protože teď se to označí jen
kliknutím na text, se s tím zas peru. xD
zkoušel jsem si udělat metodu na listview po kliknutí že se mi uloží
pozice x y myši a podle toho jsem to chtěl nějak porovnávat.. zkoušel jsem
to takhle
// metoda click na listview
p = ServerList.PointToClient(Cursor.Position);
// draw item
if (e.Item.Index == pv.LastIndex && p.X <= e.Item.Bounds.Right && p.Y <= e.Item.Bounds.Top)
// kreslím selected item
Samozřejmě to nefunguje nenakopnul bys mě nějak prosím? Díky
BTW pohyb selected itemů je i podle šipek, takže ty asi fungovat nebudou
když se to nějakým způsobem udělá přes ten point a ty šipky jsou tam
také dost potřeba.
EDIT ještě jsem zkoušel nějakým způsobem předělat velikost
Item.Bounds ale to mě nepustilo
to by bylo asi moc jednoduchý
David Jančík:4.2.2013 7:39
Ten ListView co mám v ISIMu jsi nezkoušel? Já tam používám
Tile
a nastavim mu velikost, aby mi zabíral ptořebný místo.
Aktivivní (klikací) oblast je pak po celé ploše tilu. Takže nemusíš nic
podmínkovat.
Зайчик:4.2.2013 9:10
Já bych to 'Tile' rád, ale když nastavím 'view = tile' tak se mi
'listview' nevykresluje xD prostě ten 'DrawItem' nic nedělá
Zobrazeno 42 zpráv z 42.