AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX Blogs
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 09.03.2008, 23:20   #1  
Blog bot is offline
Blog bot
Участник
 
25,631 / 848 (80) +++++++
Регистрация: 28.10.2006
Ruslan Goncharov: Scrolling in AX 3.0 without dll
Источник: http://rusgon.blogspot.com/2008/03/s...thout-dll.html
==============


As is well known in AX 3.0 it's unable to scroll objects (first of all Groups etc.) in the form. This feature is present since AX4 and supported, as far as I know by axScroll.dll.
Honestly, I'm not a big worshipper of using side components. On the other hand I've been thinking about how to implement scrolling feature in AX3.
About one year ago there was published very interesting project Capturando el WindowProc desde Axapta by Manekaze
In this project the author showed a possibility to trap keyboard events using API in AX.So why don't capture the scrollbar events.
What we have to do:</br>1. Apply scrollable style for the window which we are going to scroll.</br>2. Trap scroll events in AX.</br>3. Scroll the window according scrollbar positions.</br>
Let's go.
- Apply scrollable style for the window which we are going to scroll
Setting scrollable style for the window is pretty easy:
X++:
WinApi::showScrollbar(handle, #SB_BOTH, true);
By the way we need to set some parameters for vertical and horizontal scrollbars
X++:
//                            pos pSize  min max
WinApi::setScrollInfo(handle, 0, 20,    0, 100, true, #SB_HORZ);
WinApi::setScrollInfo(handle, 0, 20,    0, 100, true, #SB_VERT);
and get back these parameters
X++:
   cScrollInfoH = WinApi::getScrollInfo(handle, #SB_HORZ);
    xOffset      = conpeek(cScrollInfoH, #pos);
    xScroll      = conpeek(cScrollInfoH, #maxValue);
    xSize        = conpeek(cScrollInfoH, #pageSize);
   cScrollInfoV = WinApi::getScrollInfo(handle, #SB_VERT);
    yOffset      = conpeek(cScrollInfoV, #pos);
    yScroll      = conpeek(cScrollInfoV, #maxValue);
    ySize        = conpeek(cScrollInfoV, #pageSize);
In my case page size of each scrollbar is 20, minimum scrolling position is 0 and maximum scrolling position is 100.
- Scroll the window according scrollbar positions
Here I don't like to reinvent something new and I used standard library, which I've found here with small modificationsAs a matter of fact we need only two methods:
int Scroll_SetVert(ScrollInfo_t* pScroll, HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
int Scroll_SetHorz(ScrollInfo_t* pScroll, HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
X++:
int Scroll_SetVert(ScrollInfo_t* pScroll, HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
        {
        int               nScrollAmt ;

        switch (wScrollCmd)
                {
                case SB_TOP:
                        nScrollAmt = -pScroll->yOffset ;
                        break ;

                case SB_BOTTOM:
                        nScrollAmt = pScroll->yScroll - pScroll->yOffset ;
                        break ;

                case SB_PAGEUP:
                        nScrollAmt = -pScroll->ySize ;
                        break ;

                case SB_PAGEDOWN:
                        nScrollAmt = pScroll->ySize ;
                        break ;

                case SB_LINEUP:
                        nScrollAmt = -pScroll->yChar ;
                        break ;

                case SB_LINEDOWN:
                        nScrollAmt = pScroll->yChar ;
                        break ;

                case SB_THUMBPOSITION:
                        nScrollAmt = wScrollPos - pScroll->yOffset ;
                        break ;

                default:
                        return ( FALSE ) ;
                }
        if ((pScroll->yOffset + nScrollAmt) > pScroll->yScroll)
                nScrollAmt = pScroll->yScroll - pScroll->yOffset ;
        if ((pScroll->yOffset + nScrollAmt) < 0)
                nScrollAmt = -pScroll->yOffset ;
        ScrollWindow( hWnd, 0, -nScrollAmt, 0, 0 ) ;
        pScroll->yOffset = pScroll->yOffset + nScrollAmt ;
        SetScrollPos( hWnd, SB_VERT, pScroll->yOffset, TRUE ) ;

        return ( TRUE ) ;

        } // end of Scroll_SetVert()

int Scroll_SetHorz(ScrollInfo_t* pScroll, HWND hWnd, WORD wScrollCmd, WORD wScrollPos)
        {
        int               nScrollAmt ;

        switch (wScrollCmd)
                {
                case SB_TOP:
                        nScrollAmt = -pScroll->xOffset ;
                        break ;

                case SB_BOTTOM:
                        nScrollAmt = pScroll->xScroll - pScroll->xOffset ;
                        break ;

                case SB_PAGEUP:
                        nScrollAmt = -pScroll->xSize ;
                        break ;

                case SB_PAGEDOWN:
                        nScrollAmt = pScroll->xSize ;
                        break ;

                case SB_LINEUP:
                        nScrollAmt = -pScroll->xChar ;
                        break ;

                case SB_LINEDOWN:
                        nScrollAmt = pScroll->xChar ;
                        break ;

                case SB_THUMBPOSITION:
                        nScrollAmt = wScrollPos - pScroll->xOffset ;
                        break ;

                default:
                        return ( FALSE ) ;
                }
        if ((pScroll->xOffset + nScrollAmt) > pScroll->xScroll)
                nScrollAmt = pScroll->xScroll - pScroll->xOffset ;
        if ((pScroll->xOffset + nScrollAmt) < 0)
                nScrollAmt = -pScroll->xOffset ;
        ScrollWindow( hWnd, -nScrollAmt, 0, 0, 0 ) ;
        pScroll->xOffset = pScroll->xOffset + nScrollAmt ;
        SetScrollPos( hWnd, SB_HORZ, pScroll->xOffset, TRUE ) ;

        return ( TRUE ) ;
        } // end of Scroll_SetHorz()
In my WinApi class I haven't found scrollWindow() method. And I've added it into WinApi class
X++:
// Created by GRR
client static int scrollWindow(int     hwnd,
                               int     XAmount,
                               int     YAmount)
{
    DLL         _winApiDLL     = new DLL('USER32');
    DLLFunction _scrollWindow  = new DLLFunction(_winApiDLL, 'ScrollWindow');

    _scrollWindow.returns(ExtTypes::DWord);
    _scrollWindow.arg(ExtTypes::DWord,
                       ExtTypes::DWord,
                       ExtTypes::DWord,
                       ExtTypes::DWord,
                       ExtTypes::DWord);

    return _scrollWindow.call(hwnd, XAmount, YAmount, 0,0);
}
Now we are ready for third step
- Trapping scroll eventsI've designed it as a new class xApplyScrolling
X++:
// Begin of xApplyScrolling class
#define.minValue(1)
#define.maxValue(2)
#define.pageSize(3)
#define.pos(4)

#define.xChar(5)
#define.yChar(5)

class xApplyScrolling
{
    #WinApi

    TrucosAx_TrapperWndProc     WndProcHScroll, WndProcVScroll;
    HWND                        handle;

    container    cScrollInfoH, cScrollInfoV;
    int          xOffset, yOffset;
    int          xScroll, yScroll;
    int          xSize,   ySize;
}

//In new() method we are installing hooks for WM_HSCROLL and WM_VSCROLL separately
void new(FormRun _element, FormControl _formControl)//HWND _HWnd
{
    handle = _formControl.hWnd();

    WndProcHScroll = new TrucosAx_TrapperwndProc(_element, handle, true);
    WndProcHScroll.InstallHook(#WM_HSCROLL, 'scrlMessageH');
    WndProcHScroll.setObject(this);

    WndProcVScroll = new TrucosAx_TrapperwndProc(_element, handle, true);
    WndProcVScroll.InstallHook(#WM_VSCROLL, 'scrlMessageV');
    WndProcVScroll.setObject(this);

    this.setScrollable();
}

//Here we set scrollable style for the window
protected void setScrollable()
{
    ;
    WinApi::showScrollbar(handle, #SB_BOTH, true);

//                 pos pSize  min max
    WinApi::setScrollInfo(handle, 0, 20,    0, 100, true, #SB_HORZ);
    WinApi::setScrollInfo(handle, 0, 20,    0, 100, true, #SB_VERT);
    cScrollInfoH = WinApi::getScrollInfo(handle, #SB_HORZ);
    xOffset      = conpeek(cScrollInfoH, #pos);
    xScroll      = conpeek(cScrollInfoH, #maxValue);
    xSize        = conpeek(cScrollInfoH, #pageSize);
    cScrollInfoV = WinApi::getScrollInfo(handle, #SB_VERT);
    yOffset      = conpeek(cScrollInfoV, #pos);
    yScroll      = conpeek(cScrollInfoV, #maxValue);
    ySize        = conpeek(cScrollInfoV, #pageSize);
}
//Here we scroll the window
protected str translateHCode(int _nScrollCode)
{
    int          nScrollAmt ;
    str          strCode;
    ;

    switch (_nScrollCode)
    {
        case #SB_BOTTOM: // Scrolls to the lower right.
            //nScrollAmt = pScroll->xScroll - pScroll->xOffset;
            nScrollAmt = xScroll - xOffset;
            strCode = 'SB_BOTTOM';
        break;

        case #SB_ENDSCROLL: // Ends scroll.
            strCode = 'SB_ENDSCROLL';
        break;

        case #SB_LINELEFT: // Scrolls left by one unit.
            nScrollAmt = -#xChar;
            strCode = 'SB_LINELEFT';
        break;

        case #SB_LINERIGHT: // Scrolls right by one unit.
            nScrollAmt = #xChar;
            strCode = 'SB_LINERIGHT';
        break;

        case #SB_PAGELEFT: // Scrolls left by the width of the window.
            //nScrollAmt = -pScroll->xSize;
            nScrollAmt = -xSize;
            strCode = 'SB_PAGELEFT';
        break;

        case #SB_PAGERIGHT: // Scrolls right by the width of the window.
            //nScrollAmt = pScroll->xSize;
            nScrollAmt = xSize;
            strCode = 'SB_PAGERIGHT';
        break;

        case #SB_THUMBPOSITION: // Scrolls to the absolute position. The current position is specified by the nPos parameter. 
            //nScrollAmt = wScrollPos - pScroll->xOffset;
            nScrollAmt = -xSize;
            strCode = 'SB_THUMBPOSITION';
        break;

        case #SB_THUMBTRACK: // Drags scroll box to the specified position. The current position is specified by  the nPos parameter.
            strCode = 'SB_THUMBTRACK';
        break;
        case #SB_TOP: // Scrolls to the upper left.
            //nScrollAmt = -pScroll->xOffset;
            nScrollAmt = -xOffset;
            strCode = 'SB_TOP';
        break;

        default:
            //return int2HEX(_nScrollCode);
            nScrollAmt = _nScrollCode/0x10000 - xOffset;
            strCode = int2HEX(_nScrollCode);
    }

    if ((xOffset + nScrollAmt) > xScroll)
        nScrollAmt = xScroll - xOffset ;
    if ((xOffset + nScrollAmt) < 0)
        nScrollAmt = -xOffset ;
//    ScrollWindow( hWnd, -nScrollAmt, 0,) ;
    WinApi::scrollWindow(handle, -nScrollAmt, 0);

    xOffset+=nScrollAmt ;
//    SetScrollPos( hWnd, SB_HORZ, pScroll->xOffset, TRUE ) ;
    WinApi::setScrollPos(handle, #SB_HORZ, xOffset, true);
    WinApi::invalidateRect(handle);

    return strCode;
}

protected str translateVCode(int _nScrollCode)
{
    int          nScrollAmt ;
    str          strCode;
    ;

    switch (_nScrollCode)
    {
        case #SB_BOTTOM: // Scrolls to the lower right.
            nScrollAmt = yScroll - yOffset;//nScrollAmt = pScroll->yScroll - pScroll->yOffset ;
            strCode = 'SB_BOTTOM';
        break;
        case #SB_ENDSCROLL: // Ends scroll.
            return 'SB_ENDSCROLL';
        break;
        case #SB_LINEDOWN: // Scrolls one line down.
            nScrollAmt = #yChar;//nScrollAmt = pScroll->yChar;
            strCode = 'SB_LINEDOWN';
        break;

        case #SB_LINEUP: // Scrolls one line up.
            nScrollAmt = -#yChar;//nScrollAmt = -pScroll->yChar;
            strCode = 'SB_LINEUP';
        break;
        case #SB_PAGEDOWN: // Scrolls one page down.
            nScrollAmt = ySize;//nScrollAmt = pScroll->ySize;
            strCode = 'SB_PAGEDOWN';
        break;

        case #SB_PAGEUP: // Scrolls one page up.
            nScrollAmt = -ySize;//nScrollAmt = -pScroll->ySize;
            strCode = 'SB_PAGEUP';
        break;

        case #SB_THUMBPOSITION: // Scrolls to the absolute position. The current position is specified by the nPos parameter.
            //nScrollAmt = wScrollPos - pScroll->yOffset;
            nScrollAmt = -ySize;
            strCode = 'SB_THUMBPOSITION';
        break;

        case #SB_THUMBTRACK: // Drags scroll box to the specified position. The current position is specified by the nPos parameter.
            return 'SB_THUMBTRACK';
        break;

        case #SB_TOP: // Scrolls to the upper left.
            nScrollAmt = -yOffset;// nScrollAmt = -pScroll->yOffset;
            strCode = 'SB_TOP';
        break;

        default:
            nScrollAmt = _nScrollCode/0x10000 - yOffset;
            strCode = int2HEX(_nScrollCode);
    }

    if ((yOffset + nScrollAmt) > yScroll)
        nScrollAmt = yScroll - yOffset;
    if ((yOffset + nScrollAmt) < 0)
        nScrollAmt = -yOffset;

    WinApi::scrollWindow(handle, 0, -nScrollAmt);
//    pScroll->yOffset = pScroll->yOffset + nScrollAmt ;
//    SetScrollPos( hWnd, SB_VERT, pScroll->yOffset, TRUE ) ;

    yOffset+=nScrollAmt;
    WinApi::setScrollPos(handle, #SB_VERT, yOffset, true);
    WinApi::invalidateRect(handle);

    return strCode;
}

// Here we process scrolling messages
protected void scrlMessageH()
{
    map     MMsgH;
    ;

    MMsgH = WndProcHScroll.GetMsg();

    this.translateHCode(MMsgH.lookup('WPARAM'));
}

protected void scrlMessageV()
{
    map     MMsgV;
    ;

    MMsgV = WndProcVScroll.GetMsg();

    this.translateVCode(MMsgV.lookup('WPARAM'));
}

// Here we finalize our class 
void finalize()
{
    WndProcHScroll.RemoveMainProc();
    WndProcVScroll.RemoveMainProc();
}
// <-- End of xApplyScrolling class
By the way there was modificated a bit TrucosAx_TrapperWndProc class. In method processMessages() in our case we need to work with class object, not with FormRun object. Here are modifications:
X++:
class TrucosAx_TrapperWndProc extends TrucosAx_TrapperBase
{
 #define.CodeSize(159) // Total bytes de codigo
  #define.InternalDataSize(16)
  #define.MaxDataelements(100) // Si se cambia se debe cambiar el codigo asm
  #Define.DataSize(16) // +16 bytes de buffer
  #Define.offsetcounter(#CodeSize + 4)
  #Define.offsetlastmsg(#CodeSize + 8)
  #Define.offsetCallwndproc(#CodeSize + 12)

  map hooks;
  #define.maxHooks(20) //si se cambia se debe cambiar el codigo asm
  Binary HooksBuffer;

    Object  object;//Created by GRR
}

//Created by GRR
void setObject(Object _object)
{
    ;
    object = _object;
}

protected void processMessages()
{ map Mmsg;
  int msgId;


  void Ejecuta( str methodname )
  {
    str func = @"void FireHook(object obj)
    {
     ;
      obj.%1();
    }";
    func = strfmt(func,methodname);
    //RunBuf(func, xelement); //Commented by GRR

    // Created by GRR -->
    if (object)
        RunBuf(func, object);
    else
        RunBuf(func, xelement);
    // Created by GRR <--
  }
;

 do
 {
  MMsg = this.GetMsg();
  if (! MMsg) continue;
  MsgId = MMsg.lookup('MSG');
  if (hooks.exists(MsgId))
  {
    Ejecuta(hooks.lookup(MsgId));

   // Si se queda el mensaje debe devolver algo en 'RESULT' en el MMSG
    if ( ! MMsg.exists('RESULT'))
     this.CallbackOriginalProc(MMsg);
  }
 } while (MMsg && this.nextmessage());
}
That's all. To work with scrollable objects we need drop a line in run() method:
X++:
public void run()
{
    super();

    applyScrolling = new xApplyScrolling(element, element.control(control::HRMPersonal));
}

// don't forget to finalize ApplyScrolling class
public void close()
{
    applyScrolling.finalize();

    super();
}

// and declare applyScrolling variable in ClassDeclaration 
xApplyScrolling applyScrolling;
Following picture demonstrates scrolling TabPage:HRMPersonal EmplTable form P.S. This project is raw enough. For example it doesn't support form resizing. Another words... to be continued.

Источник: http://rusgon.blogspot.com/2008/03/s...thout-dll.html
__________________
Расскажите о новых и интересных блогах по Microsoft Dynamics, напишите личное сообщение администратору.
 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Ruslan Goncharov: Stereogram in AX Blog bot DAX Blogs 0 30.05.2008 18:05
Ruslan Goncharov: From Microsoft Dynamics AX Programming newsgroup tricks Blog bot DAX Blogs 0 24.05.2008 00:08
Ruslan Goncharov: How to get the screenshots of all open windows in AX Blog bot DAX Blogs 0 12.01.2008 12:31
Ruslan Goncharov: How to add a document into AX programmically? (Document handling) Blog bot DAX Blogs 0 29.12.2007 19:50
Client Axapta 3.0 SP4 и Linux. Как запустить? Daiver DAX: Администрирование 10 28.06.2007 15:59

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 17:12.