Лек проблем със StringGrid

28 отговора 635 прегледа
#1

Лек проблем със StringGrid

Здравейте, имам следния въпрос:

На една форма съм поставил компонент TabbedNotebook с няколко таба и на всеки таб има по един StringGrid компонент. Дотук нищо сложно. При resize на формата се преоразмеряват колоните на гридовете равномерно, т.е. всички колони имат еднаква ширина, така че да запълват ClientWidth на контрола.

Проблемът е в това, че когато се получи resize не всички гридове се оразмеряват правилно, т.е. рефреша не е пълен за всички гридове, а само за този, чийто таб е текущо избран. При останалите гридове нещата се оправят едва след 2-3 прецъквания между табовете.
Някой има ли идея как може да се оправи това (идеята е без да правя изкуствена смяна на табовете) или е от бъгави компоненти.

За сведение: средата е Borland Delphi 6 Personal.

Благодаря предварително.

Отговор
в отговор на Daniel #2

Re: Лек проблем със StringGrid

Едва ли е от бъгъви компоненти.... той тук един по-надолу и от ADO плаче, но аз от 5-6 години не съм имал проблеми... всичко зависи от кода дето си го написал... ако дадеш някой и друг ред, може някой и да ти помогне... на мен не ми се занимава

Отговор
в отговор на Daniel #3

Ти за Win 3.1 ли пишеш?

Ти за Win 3.1 ли пишеш?
Ами като сложиш точка на прекъсван, на всеки таб ли сменяш ширината на колоните на грида? Дебъгни го по-подробно!
:)

Отговор
в отговор на NikB #4

Re: Ти за Win 3.1 ли пишеш?

Пич, ме пиша за Win 3.1. И защо мислиш че не съм го дебъгвал. Нямам навик да искам помощ от някой ако знам как да направя нещо сам. След като съм я публикувал тази тема тук явно е нещо по-странно, с което не знам как да се справя и затова моля за помощ, а не за назидателна забележка.

Отговор
в отговор на Daniel #5

Ами що те е страх да пишеш по-подробно?

Ами що те е страх да пишеш по-подробно?
Пич, като си го дебъгвал, кажи тогава:
1. В ОнРесайз, като започнеш да променяш ширините на колоните, те променят ли се или по някаква причина изглеждат като "само за четене"?
2. Ако се променят в (1), кога си възстановяват старите рамери?

Отговор
в отговор на NikB #6

Re: Ами що те е страх да пишеш по-подробно?

Казах го по-горе - при ресайз на част от гридовете има се променят ширините на колоните, но на някои не се променят. Методът, който извършва промените е един и същ за всички гридове. Проблемът е, че гридовете не винаги зацепват че трябва да си преоразмерят колоните, ами зацепват примерно след прецъкване между табовете да кажем. По-ясно от това няма как да го кажа.
Подобен проблем има с Панел компонента - при ОнРесайз по вертикала всичко бачка като хората, но по хоризонтал влиза в накакъв цикъл и се омазва. Абе изобщо боза се получава.

Отговор
в отговор на Дaниeл #7

Re: Ами що те е страх да пишеш по-подробно?

Не си казал горе, когато спреш на точка на прекъсване в ОнРесайз, как се променят някои гридове, а други не се променят. Нещо не се рабираме, моля уточни:

Как са изравнени (Align) гридовете?
Върху какво са сложени (Parent) - направо върху страницата или има панели?
Чий ресайз си прехванал?

А (ако е възможно - няма много допълнителни юнити) - можеш да ми изпратиш формата на мейла от профила.

Отговор
в отговор на Дaниeл #8

Дай сорса

Без да покажеш какво си написал няма да ни е лесно да ти намерим грешката.

Отговор
в отговор на NikB #9

Re: Ами що те е страх да пишеш по-подробно?

Добре , уточнявам:
гридовете са върху ТаббедНотбуук, част от тях са и върху панели (които са върху ТаббедНотбуук). Прихванат е ресайза на цялата форма, също така и Чейндж-а на нотбуук-а. На някои места, където има панели е прихванат ресайза на панелите.
При обработката на ресаизовете се прави изравняване на ширините на колоните, т.е. всички колони да са с еднакви ширини, а не Align (подравняване).

Отговор
в отговор на andrew_nikoloff #10

Re: Дай сорса

Общо взето това е кода:


try
intColumnWidth := ((Sender as ТStringGrid).ClientWidth - (Sender as TStringGrid).ColCount) div
(Sender as TStringGrid).ColCount;
if intColumnWidth <= 0 then Exit;
for i := 0 to (Sender as TStringGrid).ColCount-1 do
(Sender as TStringGrid).ColWidths := intColumnWidth;
(Sender as TStringGrid).Refresh;
except
end;


Отговор
в отговор на Дaниeл #11

Re: Дай сорса

Явно това което пишеш е доста секретно и няма да го публикуваш. Добре тогава. Ще трябва да ти задаваме по конкретни въпроси.
1. Какъв е този код? Явно очакваш Sender да е StringGrid-а ти. Как се вика? Защото StringGrid-а няма събитие OnResize и нещо не мога да си представя логична ситуация, в която Sender да ти е грида.
2. Как разбираш колко грида има?
3. Всички ли преоразмеряваш при промяна размера на формата?
4. След като грида не ти е "Align (подравняване)" каква ти е ползата да разширяваш колоните, ако самия грид няма да може да ги покаже, защото според твоите обяснения той би трябвало да си запази старите размери?
5. Каква е причината да установяваш неколкократно ширината на колоните на грида?
for i := 0 to (Sender as TStringGrid).ColCount-1 do
(Sender as TStringGrid).ColWidths := intColumnWidth;

Според мен няма много файда от тази работа.

Ако изпитваш затруднение да отговориш ясно и изчерпателно на тези въпроси, сросто публикувай pas и dfm файла и ще се постараем да ти помогнем.

Отговор
в отговор на Дaниeл #12

Re: уточнение

И не се викат някои събития ОнРесайз
или
след изпълнението им не променя ширината на колоните
или
след вярна промяна на ширината някой отново я променя?

Разбира се, по-добре е еднотипно и на едно място да сложиш ресайзите (например в ОнРесайз на формата).
А за Align имах предвид на грида и неговите притежатели (панели, таббеднотета, ...)
type TAlign = (alNone, alTop, alBottom, alLeft, alRight, alClient);

Отговор
в отговор на andrew_nikoloff #13

Re: Дай сорса

OK, сега ще карам подред.
Идеята е при OnResize на формата или при OnTabChange на TabbedNotebook, да се прави така че колоните да си остават с еднакви ширини и

StringGrid.GridWidth = StringGrid.ClientWidth ,

т.е. да няма бели полета след края на самата мрежа (това равенство е приблизително, тъй като се вземат предвид и ColCount, т.е. нещо от рода

StringGrid.GridWidth+StringGrid.ColCount = StringGrid.ClientWidth).

Гридовете си имат Anchors, така че при промяна размера на формата, гридовете също променят своите ClientWidth и ClientHeight. Функцията, която публикувах по-горе се вика няколко пъти (при OnResize на формата и при OnTabChange на TabbedNotebook), като всеки път като параметър се задава грида, за който ще се извършва съответното изравняване на колоните.
Проблема е, че за първия грид, който се преоразмерява, при него нещо не зацепва както трябва и след прецъкване по табовете на TabbedNotebook-a нещата се оправят, а не би трябвало да се прецъква за да влязат нещата в ред.

Подобен проблем се получава като се преоразмерява панел по ширина, тогава OnResize се вика няколко пъти при смяна на ширината, което ми е много чудно, понеже при смяна на височина се извиква само веднъж (става дума за промяна на ClientWidth и ClientHeight).

И между другото за сорса : това което съм публикувал е част от сорса, който разучавам на една програма, но при дебъг не можах да открия защо прави така (отделно че сорса на програмата е структуриран отвратително - функции от по 200 реда код без грам коментар, а е писан още на Delphi 1 и то от няколко човека един след друг).

Това е причината, за да не публикувам целия сорс, още повече че не е и съвсем редно да публикувам фирмен сорс в нет-а.

Сега след като обясних за какво става дума се надявам някой да ме е разбрал и да пробва да ми помогне, щото моите идеи ги изчерпах :(

Отговор
в отговор на Daniel #14

Re: Дай сорса

Така е по-добре. Извинявай за малко по-грубия тон, но постинга ти съвсем заприлича на "написах си една програма, ама тя неработи. аз грешки нямам, ама тя пак не прави каквото искам. няма да ви кажа каква е, ама моля помогнете"
До колкото разбирам имаш няколко страници и на всяка има по един (или повече) гридове. Ако греша - поправи ме!
Ето какво бих направил аз:
1. Панелите едва ли трябва да имат нещо на OnResize. Предполагам, че те ще си променят размера само в следствие преоразмеряването на формата.
2. Ще централизирам малко нещата - ще махна кода при Change на TabbedNotebook-а, а при промяна на размера на формата ще преизчислявам ширината на колоните на всички гридове. Ще се завъртя рекурсивно по контролите на формата и ще изпълня процедурата за всеки грид, който намеря.
3. В последната колона на грида ще натрупвам закръглението. Т.е. в ColWidths пропъртито (при постването се е махнало [ i ]-то след ColWidths в твоя пример. Форума го разпознава, като команда за форматиране) ще напълня ColCount-1 пъти ClientWidth div ColCount, а ширината на последната колона ще е остатъка.
4. Не си казал имаш ли FixedCols? Ако да - може би няма да променям нейната/тяхната ширината. Това ще се отрази на сметката от предната точка, като ще трябва да разпределям останалите колони не по цялата ширина на грида.

Не знам какво се е омазало при преоразмеряването по вертикала, но е малко трудно да дебъгваш такъв код по стандартния начин. Аз щях да си сложя някъде едно мемо и в него да пълня какво ми се случва по време на преоразмеряването. Също така щях да си запомня някъде предишната ширина на формата и да я сравнявам с новата. Все пак ако променям само височината - няма смисъл да смятам наново всичко.

Не знам до колко съм ти помогнал, но без да имам достъп до кода не мога да направя много. Проблемът вероятно си е от лошо написан сорс, така че седни, поизчисти го и кажи после какво е станало! Успех!

Отговор
в отговор на andrew_nikoloff #15

Re: Дай сорса

Andrew, всичко хубаво, но това за рекурсията защо е ?
Аз така или ина4е извиквам тая процедура за всеки грид от TabbedNotebook-a, то така или ина4е единствените компоненти във формата са тоя Нотбук, гридовете и 1-2 панела. Иначе грешката от преоразмеряване как да я избегна, все пак ширината на колоните е цяло число ?
Освен това само ще те коригирам - става въпрос за преоразмеряване по хоризонтала, а не по вертикала. По вертикала си бачка като хората, само по хоризонтал се маже, ама не можах да го открия за съжаление :(
Впрочем това за чистенето на кода е добра идея, ама не зависи от мен - работи се по спецификации и просто няма начин, не мога да разкарам нищо, щото иначе лошо за мен :(
Иначе и на мен не ми харесва една функция да е 200 реда и без грам коментар, да не говорим че всеки който е писал по кода си е оставил ръцете - колкото човека, толкова и стилове :(

Иначе мерси за съветите, ще пробвам да го тествам на моя комп да видя дали и там ще е същото или ще се получи разлика.

Отговор
в отговор на Daniel #16

Re: Дай сорса

Нещо не сме се доразбрали май...
всичко хубаво, но това за рекурсията защо е ?
Ами при условие, че си знаеш кои и колко са гридовете, можеш просто да си извикаш процедурата съответния брой пъти, но това предполага промяна на кода при добавяне/премахване на грид. А това не е хубаво. Ако приемем, че формата ти е собственик на всички гридове, то тогава ще е достатъчно да се завъртиш само по нейните контроли. Но понеже не знам дали е така (а и понеже не знам дали няма в бъдеще да се промени) ти предложих въртейки се по тях да се викаш рекурсивно и да навлизаш в дълбочина.
Иначе грешката от преоразмеряване как да я избегна, все пак ширината на колоните е цяло число ?
Май ще е най-ясно да ти дам пример:

По твоя метод:
Имаш 10 колони и грид с ширина 99
99 div 10 = 9
10 колони по 9 пиксела = 90 пиксела - остава празно поле 99 - 90 = 9 пиксела.

По моя метод:
Round(99 / 10) = Round(9.9) = 10
Ширина на колони 1 до 9 = 10
Ширина на последната колона = 99 - (10 * 9) = 9

А сега на pascal:
ColWidth := Round(Grid.ClientWidth / Grid.ColCount);
LastColWidth := Grid.ClientWidth - ColWidth * (Grid.ColCount - 1);
Grid.ColWidths.Clear;
for idx := 0 to Grid.ColCount - 2 do Grid.ColWidths.Add(IntToStr(ColWidth));
Grid.ColWidths.Add(IntToStr(LastColWidth));

просто няма начин, не мога да разкарам нищо
Според мене това си е чисто и просто отстраняване на грешки. Не виждам какво ти пречи спецификацията. В края на краищата те би трябвало да се оправят, нали?

Отговор
в отговор на andrew_nikoloff #17

Re: Дай сорса

Би трябвало, ама ако имаш разрешение да махаш сорс :(
А като нямам си седи старото положение. С други думи казано по-добре да се преструктутрира сорса на програмата, защото има неща от Делфи 1 до Делфи 6, а сам знаеш каква е разликата между двете. Абе изобщо гадна работа, с която трябва да се оправя някак си.

Отговор
в отговор на Daniel #18

Re: Лек проблем със StringGrid и Панел

Между другото ето един примерен сорс относно проблема с ширината на панела:


procedure TForm1.Panel1Resize(Sender: TObject);
var GridW, DifferenceW : integer;
begin
GridW := StringGrid2.GridWidth;
DifferenceW := GridW + StringGrid2.ColCount - StringGrid2.ClientWidth;
if DifferenceW < 0 then
Panel1.ClientWidth := Panel1.ClientWidth - DifferenceW;
end;


Панела е контейнер за СтрингГрид2. Идеята е когато се преоразмери панела, той да не се разширява толкова, че да се покажат белите полета на СтрингГрид-а. Проблема е, че като влезе почва да цикли и не ще да излезе от обработчика на събитието.
Този номер го прави само когато се променя ширината, когато се променя височината няма проблем.
Някакви идеи ?

Отговор
в отговор на Дaниeл #19

Re: Лек проблем със StringGrid и Панел

Имаше един такъв майтапчийски речник, в който за рекурсия пишеше:
Рекурсия - вж. Рекурсия
Та и ти така - в OnResize на панела сменяш ширината на панела, което предизвиква OnResize, където променяш ширината на панела, което предизвиква OnResize....

Отговор
в отговор на Daniel #20

Нямаш разрешение ????

Какво значи, че нямаш разрешение да махаш сорс ???
Вие как програмирате там бе ???

Отговор