Вопросы по LCL

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Re: Вопросы по LCL

Сообщение zub » 26.06.2010 14:28:37

Хм... Странно, что не работает. А отрисовка где?

В OnPaint. Уже паправил, GetDC заменил на canvas.Handle - всё заработало.
В классической теме рисовалось, в XP нет.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение zub » 27.06.2010 17:05:27

Так и не выходит победить TMemo.

нужно както заставить TMemo.Append() не добавлять автоматом #13#10 в конец кажной строки.
Вариант с ручным убиранием #13#10 с помощью SelStart, SelLength, ClearSelection не подошел изза сбивания положения скрола (теряет текущее положение и показывает текст с начала) и тормознутости на больших текстах.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение Nik » 27.06.2010 19:51:18

нужно както заставить TMemo.Append() не добавлять автоматом #13#10 в конец кажной строки.

Может проще написать свою функцию?
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Вопросы по LCL

Сообщение А.Н. » 27.06.2010 21:28:01

Вряд ли возможно.
А для чего, если есть свойство Text? Может, проще действительно написать функцию, убирающую #13#10?
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Вопросы по LCL

Сообщение zub » 27.06.2010 23:12:02

А для чего, если есть свойство Text? Может, проще действительно написать функцию, убирающую #13#10?

Все операции с Text или SelText вызывают перегон текста из\в контрол что очень медленно. win-only добавление строки (или убирание #13#10) написать не трудно, думал есть штатный кроссплатформенный способ.
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение zub » 01.07.2010 15:06:34

Еще бы хотелось кроссплатформенный таймер тикающий независимо от занятости приложения. ТТimer тикает только козда приложение простаивает
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение Nik » 02.07.2010 11:05:51

Еще бы хотелось кроссплатформенный таймер тикающий независимо от занятости приложения. ТТimer тикает только козда приложение простаивает

Может стоит создать таймер в отдельном потоке?
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Вопросы по LCL

Сообщение А.Н. » 04.07.2010 13:27:08

О, таймеры - это всегда пожалуйста. :mrgreen:

В window$ существует единственный путь получить нормальный таймер.
Это QueryPerformanceCounter(...).
К которой прилагается куча сексуальных прелестей, типа GetProcessAffinityMask/SetThreadAffinityMask.
Без этих поток может выполняться на разных ЦП/ядрах. Что, естественно, таймеру не помогает.
Плюс, данная функция зависит от железа. Не везде есть точные таймеры (сейчас, наверное, везде).

Но, помимо данной функции, получить нормальный таймер на виндавс возможности - нет.

Есть ещё команда rdtsc (кстати, не помню, но QueryPerformanceCounter может через неё и реализован, хотя не помню совсем). Но это не труЪ. Мало того, что привязка к вполне определённому типу процессоров (хотя не очень-то это и важно), так ещё у неё могут быть "особенности", которые придётся учитывать.

Таймеры на Linux и подобном реализуются через функцию clock(). Через что реализуется эта функция я не знаю.
В lazarus, кажется, она есть, если поискать или поспрашивать. Плюс, вроде бы, к lazarus возможно подключить libc, если сильно приспичит.

Тут не знаю. А искать сейчас просто нет времени и сил.

Предлагаю таймер, выдранный из Ogre3D и слегка модифицированный (добавлена возможность паузы).

OgreTimer.h:
Код: Выделить всё
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#ifndef __Win32Timer_H__
#define __Win32Timer_H__

#define WIN32_LEAN_AND_MEAN
#ifndef NOMINMAX
#  define NOMINMAX // required to stop windows.h messing up std::min
#endif
#include <windows.h>
#include <time.h>
#include <system.hpp>

namespace Ogre
{
   class Timer
   {
   private:
      clock_t mZeroClock;
      clock_t mPauseClock;

      DWORD mStartTick;
      DWORD mPauseTick;

      LONGLONG mLastTime;

      LARGE_INTEGER mStartTime;
      LARGE_INTEGER mPauseTime;

      LARGE_INTEGER mFrequency;

                DWORD mTimerMask;

      BOOL paused;
    public:
                /** Timer constructor.  MUST be called on same thread that calls getMilliseconds() */
                Timer();
                ~Timer();

                /** Method for setting a specific option of the Timer. These options are usually
            specific for a certain implementation of the Timer class, and may (and probably
            will) not exist across different implementations.  reset() must be called after
                        all setOption() calls.
                        @par
                        Current options supported are:
                        <ul><li>"QueryAffinityMask" (DWORD): Set the thread affinity mask to be used
                        to check the timer. If 'reset' has been called already this mask should
                        overlap with the process mask that was in force at that point, and should
                        be a power of two (a single core).</li></ul>
            @param
                strKey The name of the option to set
            @param
                pValue A pointer to the value - the size should be calculated by the timer
                based on the key
            @return
                On success, true is returned.
            @par
                On failure, false is returned.
        */
      bool setOption(const AnsiString& strKey, const void* pValue);

                /** Resets timer */
                void reset();

      // Pause timer
                void pause();

      // Resume timer
                void resume();

      BOOL is_paused() const;
                /** Returns milliseconds since initialisation or last reset */
                unsigned long getMilliseconds();

                /** Returns microseconds since initialisation or last reset */
                unsigned long getMicroseconds();

                /** Returns milliseconds since initialisation or last reset, only CPU time measured */
                unsigned long getMillisecondsCPU();

                /** Returns microseconds since initialisation or last reset, only CPU time measured */
                unsigned long getMicrosecondsCPU();
    };
}
#endif


OrgeTimer.cpp:
Код: Выделить всё
/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreTimer.h"
//---------------------------------------------------------------------------
#include "Functions.h"
using namespace Ogre;

//-------------------------------------------------------------------------
Timer::Timer() : mTimerMask(0)
{
   reset();
}
//-------------------------------------------------------------------------
Timer::~Timer()
{
}
//-------------------------------------------------------------------------
bool Timer::setOption( const String & key, const void * val )
{
   if (key == "QueryAffinityMask")
   {
      // Telling timer what core to use for a timer read
      DWORD newTimerMask = *static_cast <const DWORD*> ( val );

      // Get the current process core mask
      DWORD procMask;
      DWORD sysMask;
      #if _MSC_VER >= 1400 && defined (_M_X64)
      GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask,
         (PDWORD_PTR)&sysMask);
      #else
      GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
      #endif

      // If new mask is 0, then set to default behavior, otherwise check
      // to make sure new timer core mask overlaps with process core mask
      // and that new timer core mask is a power of 2 (i.e. a single core)
      if(( newTimerMask == 0 ) || ((( newTimerMask & procMask) != 0) &&
         is2power(newTimerMask)))
      {
         mTimerMask = newTimerMask;
         return true;
      }
   }
   return false;
}
//-------------------------------------------------------------------------
void Timer::reset()
{
   // Get the current process core mask
   DWORD procMask;
   DWORD sysMask;
   #if _MSC_VER >= 1400 && defined (_M_X64)
   GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask,
      (PDWORD_PTR)&sysMask);
   #else
   GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
   #endif

   // If procMask is 0, consider there is only one core available
   // (using 0 as procMask will cause an infinite loop below)
   if (procMask == 0) procMask = 1;

   // Find the lowest core that this process uses
   if (mTimerMask == 0)
   {
      mTimerMask = 1;
      while ((mTimerMask & procMask) == 0)
      {
         mTimerMask <<= 1;
      }
   }

   HANDLE thread = GetCurrentThread();

   // Set affinity to the first core
   DWORD oldMask = SetThreadAffinityMask(thread, mTimerMask);

   // Get the constant frequency
   QueryPerformanceFrequency(&mFrequency);

   // Query the timer
   QueryPerformanceCounter(&mStartTime);
   mStartTick = GetTickCount();

   // Reset affinity
   SetThreadAffinityMask(thread, oldMask);

   mLastTime   = 0;
   mZeroClock  = clock();
   paused      = false;   
}
//-------------------------------------------------------------------------
void Timer::pause()
{
   // Запоминаю время паузы
   // Get the current process core mask
   DWORD procMask;
   DWORD sysMask;
   #if _MSC_VER >= 1400 && defined (_M_X64)
   GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask,
      (PDWORD_PTR)&sysMask);
   #else
   GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
   #endif

   // If procMask is 0, consider there is only one core available
   // (using 0 as procMask will cause an infinite loop below)
   if (procMask == 0) procMask = 1;

   // Find the lowest core that this process uses
   if (mTimerMask == 0)
   {
      mTimerMask = 1;
      while ((mTimerMask & procMask) == 0)
      {
         mTimerMask <<= 1;
      }
   }

   HANDLE thread = GetCurrentThread();

   // Set affinity to the first core
   DWORD oldMask = SetThreadAffinityMask(thread, mTimerMask);

   // Get the constant frequency
   QueryPerformanceFrequency(&mFrequency);

   // Query the timer
   QueryPerformanceCounter(&mPauseTime);
   mPauseTick = GetTickCount();

   // Reset affinity
   SetThreadAffinityMask(thread, oldMask);

   mLastTime = 0;
   mPauseClock = clock();
   paused      = true;
}
//-------------------------------------------------------------------------
void Timer::resume()
{
   // Добавляю к начальному времени промежуток, прошедший с момента паузы
   clock_t mResumeClock;
   DWORD mResumeTick;
   LARGE_INTEGER mResumeTime;
   // Get the current process core mask
   DWORD procMask;
   DWORD sysMask;
   #if _MSC_VER >= 1400 && defined (_M_X64)
   GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)&procMask,
      (PDWORD_PTR)&sysMask);
   #else
   GetProcessAffinityMask(GetCurrentProcess(), &procMask, &sysMask);
   #endif

   // If procMask is 0, consider there is only one core available
   // (using 0 as procMask will cause an infinite loop below)
   if (procMask == 0) procMask = 1;

   // Find the lowest core that this process uses
   if (mTimerMask == 0)
   {
      mTimerMask = 1;
      while ((mTimerMask & procMask) == 0)
      {
         mTimerMask <<= 1;
      }
   }

   HANDLE thread = GetCurrentThread();

   // Set affinity to the first core
   DWORD oldMask = SetThreadAffinityMask(thread, mTimerMask);

   // Get the constant frequency
   QueryPerformanceFrequency(&mFrequency);
   
   // Query the timer
   QueryPerformanceCounter(&mResumeTime);
   mStartTime.QuadPart  += mResumeTime.QuadPart - mPauseTime.QuadPart;
   mResumeTick          = GetTickCount();
   mStartTick           += mResumeTick - mPauseTick;

   // Reset affinity
   SetThreadAffinityMask(thread, oldMask);

   mLastTime      = 0;
   mResumeClock   = clock();
   mZeroClock     += mResumeClock - mPauseClock;
   paused         = false;
}
//-------------------------------------------------------------------------
BOOL Timer::is_paused() const
{
   return(paused);
}
//-------------------------------------------------------------------------
unsigned long Timer::getMilliseconds()
{
   LARGE_INTEGER curTime;

   HANDLE thread = GetCurrentThread();

   // Set affinity to the first core
   DWORD oldMask = SetThreadAffinityMask(thread, mTimerMask);

   // Query the timer
   QueryPerformanceCounter(&curTime);

   // Reset affinity
   SetThreadAffinityMask(thread, oldMask);

   LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;

   // scale by 1000 for milliseconds
   unsigned long newTicks = (unsigned long)
      (1000 * newTime / mFrequency.QuadPart);

   // detect and compensate for performance counter leaps
   // (surprisingly common, see Microsoft KB: Q274323)
   unsigned long check = GetTickCount() - mStartTick;
   signed long msecOff = (signed long)(newTicks - check);
   if (msecOff < -100 || msecOff > 100)
   {
      // We must keep the timer running forward :)
      LONGLONG adjust =
         min(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);

      mStartTime.QuadPart += adjust;
      newTime -= adjust;

      // Re-calculate milliseconds
      newTicks = (unsigned long)(1000 * newTime / mFrequency.QuadPart);
   }

   // Record last time for adjust
   mLastTime = newTime;

   return newTicks;
}
//-------------------------------------------------------------------------
unsigned long Timer::getMicroseconds()
{
   LARGE_INTEGER curTime;

   HANDLE thread = GetCurrentThread();

   // Set affinity to the first core
   DWORD oldMask = SetThreadAffinityMask(thread, mTimerMask);

   // Query the timer
   QueryPerformanceCounter(&curTime);

   // Reset affinity
   SetThreadAffinityMask(thread, oldMask);

   LONGLONG newTime = curTime.QuadPart - mStartTime.QuadPart;

   // get milliseconds to check against GetTickCount
   unsigned long newTicks =
      (unsigned long)(1000 * newTime / mFrequency.QuadPart);

   // detect and compensate for performance counter leaps
   // (surprisingly common, see Microsoft KB: Q274323)
   unsigned long check = GetTickCount() - mStartTick;
   signed long msecOff = (signed long)(newTicks - check);
   if (msecOff < -100 || msecOff > 100)
   {
      // We must keep the timer running forward :)
      LONGLONG adjust =
         min(msecOff * mFrequency.QuadPart / 1000, newTime - mLastTime);
         
      mStartTime.QuadPart += adjust;
      newTime -= adjust;
   }

   // Record last time for adjust
   mLastTime = newTime;

   // scale by 1000000 for microseconds
   unsigned long newMicro =
      (unsigned long)(1000000 * newTime / mFrequency.QuadPart);

   return newMicro;
}
//-------------------------------------------------------------------------
unsigned long Timer::getMillisecondsCPU()
{
   if (paused) resume();
   clock_t newClock = clock();
   return(unsigned long)((float)(newClock - mZeroClock) /
      ((float)CLOCKS_PER_SEC / 1000.0 ));
}
//-------------------------------------------------------------------------
unsigned long Timer::getMicrosecondsCPU()
{
   if (paused) resume();
   clock_t newClock = clock();
   return(unsigned long)((float)(newClock - mZeroClock) /
      ((float)CLOCKS_PER_SEC / 1000000.0 )) ;
}
//-------------------------------------------------------------------------


Оригинальный таймер (при беглом просмотре, он не поменялся, ну, кроме лицензии) вы можете найти здесь:
https://svn.ogre3d.org/svnroot/ogre/trunk/OgreMain/
Главный заголовочный файл:
https://svn.ogre3d.org/svnroot/ogre/tru ... greTimer.h

Там, также, есть таймер под Linux и macosx.

Думаю понятно, но на всякий случай. Запускать таймеры надо в отдельном потоке, примерно таким образом:
Код: Выделить всё
//---------------------------------------------------------------------------
void __fastcall TProgramLogic::MainProc()
{
   while (FTimerEnabled)
   {
      FCounter = FTimer.getMilliseconds();
      if (FNSEventEnabled && FNSEventPeriod)
      {
         if (((FCounter - FNSEventStartTime) / 1000) >= FNSEventPeriod)
         {
            FNSEventStartTime = FCounter;
            FEventMechanism->GenerateEvent(evtNS);
         }
      }
      if ((!FSecondmeterMode && (FCounter >= FMaximumMs)) /* ||
         ((FMaximumPeriod) && (FCurrentPeriod >= FMaximumPeriod))*/
      )
      {
         // Проверка на число периодов делается в AddToLog
         PauseTimer(ttcAuto);
      }

      Application->ProcessMessages();
      Repaint();
   }
}

...
   FTimer.reset();
   MainProc();


P.S.:
Помимо этого, lazarus, кажется имеет какой-то компонент - точный таймер. Я потыкал по вкладкам, но не нашёл. Возможно мне привиделось ранее.

Добавлено спустя 7 минут 6 секунд:
Да, конечно же, всё-равно не удастся получить точный таймер. Поскольку виндовс - отстой не система реального времени. Для этого потребуется написание драйвера и ещё много-много интересных вещей.
Но, думаю, что этого таймера для ваших задач вполне хватит.

Его, кстати, не обязательно переписывать. Я бы в библиотеку какую-нибудь загнал и не мучался. В dll в винде, например.
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Вопросы по LCL

Сообщение zub » 05.07.2010 00:24:31

Nik
>>Может стоит создать таймер в отдельном потоке?
А.Н.
>>Но, думаю, что этого таймера для ваших задач вполне хватит.
Спасибо, но RDTSC для меня будет лишним. Городить потоки под таймер - к счастью я не пишу программу управления термоядерными реактороми))
в винде пользовался:
Код: Выделить всё
function timeSetEvent(uDelay, uReolution: UINT; lpTimeProc: GDBPointer;dwUser: DWord; fuEvent: UINT): GDBInteger; stdcall; external 'winmm';
function timeKillEvent(uID: UINT): GDBInteger; stdcall; external 'winmm';

вполне устраивало

Сегодня наконецто ZCAD скомпилировался и запустился под linux`ом, много чего зарезано, но всеравно приятно...
места которые думал не заработают - работают с полпинка...
фрагменты простые как валенок - валятся или не компилируются, спасибо CASEзависимости! нафига она нужна и как с ней бороться? запарился руками править исходники и рантайм файлы.

Также удивило отсутствие в линукс версии LCL TFileVersionInfo и TPageControl.DoChange
как получить версию файла?
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение А.Н. » 05.07.2010 00:36:34

Спасибо, но RDTSC для меня будет лишним. Городить потоки под таймер - к счастью я не пишу программу управления термоядерными реактороми))

Если соберётесь писать её под window$ - предупредите, я куплю себе тапочки. ;)

в винде пользовался:

Плохая идея. Мультимедийные таймеры ненадёжны. Они отстают очень сильно, при загруженной системе.

Сегодня наконецто ZCAD скомпилировался и запустился под linux`ом, много чего зарезано, но всеравно приятно...

Поздравляю.

спасибо CASEзависимости! нафига она нужна и как с ней бороться? запарился руками править исходники и рантайм файлы.

Что есть CASE зависимость?

как получить версию файла?

Я не знаю что такое TFileVersionInfo. Но могу предположить, что если это получение VersionInfo, то под linux это работать, скорее всего, не будет.
VersionInfo - это хранящееся в ресурсах данные о версии PE файла. Структуры ELF я совсем не знаю, но полагаю, что VersionInfo туда не добавляется.

Добавлено спустя 34 секунды:
Может, возможно и без него обойтись?
А.Н.
постоялец
 
Сообщения: 230
Зарегистрирован: 13.03.2010 12:23:58

Re: Вопросы по LCL

Сообщение zub » 05.07.2010 01:23:17

Плохая идея. Мультимедийные таймеры ненадёжны. Они отстают очень сильно, при загруженной системе.

мне точность не особо нужна: мерю время рендера, разных продолжительных непрерывных процессов, жду полсекунды когда пользователь остановил мышь над какимлибо объектом. первые 2 пункта - только для отладки, с последним справится и TTimer, вопрос был из соображений любознательности, если нет простого решения, то проблема подождет до лучших времен.

Что есть CASE зависимость?

чувствительность к регистру в именах файлов. ИМХО очень неудобно, у меня везде были названия типа UGDBBillOfMaterial.pas с небольшими вариациями регистра))

Я не знаю что такое TFileVersionInfo. Но могу предположить, что если это получение VersionInfo, то под linux это работать, скорее всего, не будет.
VersionInfo - это хранящееся в ресурсах данные о версии PE файла. Структуры ELF я совсем не знаю, но полагаю, что VersionInfo туда не добавляется.
Может, возможно и без него обойтись?

Я тоже незнаю хранится это в ELF или нет, однако в линуксовом IDE эти настройки есть... Обойтись конечно можно, но кроссплатформенность постепенно превращается в вырезанье не очень нужных, но приятных фич :(
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение Mr.Smart » 05.07.2010 10:10:14

zub
Сам не пробовал, но в компоненте TRxVersionInfo из пакета RxFPC by alexs есть чтение версии из ELF.
Код: Выделить всё
...
  {$IFDEF WINDOWS}
  Reader:=TWinPEImageResourceReader.Create;
  {$ENDIF}
  {$IFDEF LINUX}
  Reader:=TElfResourceReader.Create;
  {$ENDIF}   
...

п.с. это только относится к версии FPC 2.4.0 +
Mr.Smart
долгожитель
 
Сообщения: 1796
Зарегистрирован: 29.03.2008 01:01:11
Откуда: из леса!

Re: Вопросы по LCL

Сообщение zub » 05.07.2010 14:04:32

Mr.Smart
Спасибо. посмотрю
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение zub » 07.07.2010 16:47:23

Еще глупый вопрос - как правильно создать сплитер в рантайме?
мне нужно разделить сплитером две панели. в винде и в линуксе результат выглядит по разному
Код: Выделить всё
uppanel.align:=alClient;
spliter.allign:=alBottom;
downpanel.allign:=alBottom;

такая последовательность создания в винде выглядит правильно, в линуксе сплитер прилипает к низу окна
zub
долгожитель
 
Сообщения: 2887
Зарегистрирован: 14.11.2005 23:51:26

Re: Вопросы по LCL

Сообщение Brainenjii » 07.07.2010 16:53:49

Задать после align'а ещё и top... Скажем
Код: Выделить всё
uppanel.align:=alClient;
spliter.align:=alBottom;
downpanel.align:=alBottom;
Spliter.Top := 0;

Кстати, я бы на месте компилятора на 2 и 3 строчку ругнулся ^_^
Аватара пользователя
Brainenjii
энтузиаст
 
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Пред.След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex [Bot] и гости: 220

Рейтинг@Mail.ru