草庐IT

c++ - 当用户将 ListView 项目拖到其滚动条上时,执行默认滚动行为

coder 2023-11-17 原文

简介:

我的母语不是英语,也不是很有经验的程序员。

我遇到了一个很难描述的问题,所以在阅读这个问题时请牢记这一点。

相关信息:

我正致力于在 ListView 中实现拖放功能。我只想能够在 ListView 中重新排列行,不会将项目拖到其他窗口。

我不想使用 OLE 来执行此操作,而且我对在许多链接上找到的“默认”实现不满意。

我对如何执行此操作有自己的想法,但我的经验不足使我无法实现我的想法。

我正在使用 Visual Studio、C++ 和原始 WinAPI 进行开发。我没有使用任何库,也不想现在就开始使用它们。

问题:

我希望实现以下行为:

用户按下鼠标左键并开始拖动项目 -> 用户将鼠标移到垂直滚动条上 -> 发生默认滚动。

由于滚动条算作非客户区,这意味着我必须以某种方式为 WM_NCMOUSEMOVEWM_NCLBUTTONDOWN 执行默认行为,但我不知道该怎么做。

让我试着更好地解释一下我的意思:

当您拖动项目时,应用程序指示当鼠标悬停在项目上(在 ListView 的客户区中)时项目将被放置的位置是合乎逻辑的。

当您将项目拖到滚动条上时,很明显用户不能将项目放在那里。而不是指示无效的放置点(通过更改光标,例如,像 OLE 那样),我希望执行以下操作:

我希望执行默认的滚动条行为(就好像用户根本不拖动项目一样)。就好像用户将鼠标悬停在滚动条上,按下并按住鼠标左键,并可选择向上或向下移动鼠标。

当用户将鼠标从滚动条移回 ListView 的客户区时,拖放继续。

中南合作商会

我的英语不够好,无法进行适当的研究(就像我通常在发帖之前所做的那样),而且我不知道有任何应用程序有这种行为,所以我真的很难尝试解决这是我自己的。

不过,在浏览 Raymond Chen 的博客时,我想到了一个主意。

下面的示例代码完美地演示了我上面谈到的行为。它并不完美,但它最接近实现我想要的行为。

创建空的 C++ 项目并简单地复制/粘贴下面的代码。

然后尝试将项目拖动到滚动条上。

重要提示:我没有实现项目的重新排列,也没有改变光标形状以保持代码最少。此 SSCCE 的目的是展示我想要的行为。

#include <windows.h>
#include <windowsx.h>   // various listview macros etc
#include <CommCtrl.h>
#include <stdio.h>      // swprintf_s()

// enable Visual Styles
#pragma comment( linker, "/manifestdependency:\"type='win32' \
                         name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
                         processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
                         language='*'\"")

// link with Common Controls library
#pragma comment( lib, "comctl32.lib")

//global variables
HINSTANCE hInst;
BOOL g_bDrag;

// subclass procedure for listview -> implements drag and drop
LRESULT CALLBACK DragAndDrop(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam,
    UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (message)
    {
    case WM_CAPTURECHANGED:  // in case user ALT+TAB to another window, for example
    {
        g_bDrag = FALSE;
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);

    case WM_LBUTTONUP:      // do the drop ->omitted for brewity
    {
        if (g_bDrag)
        {
            POINT pt = { 0 };
            pt.x = GET_X_LPARAM(lParam);
            pt.y = GET_Y_LPARAM(lParam);

            g_bDrag = FALSE;
            ReleaseCapture();
        }
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);

    case WM_MOUSEMOVE:
    {
        if (g_bDrag)
        {
            POINT pt = { 0 };
            pt.x = GET_X_LPARAM(lParam);
            pt.y = GET_Y_LPARAM(lParam);

            LVHITTESTINFO lvhti = { 0 };
            lvhti.pt = pt;
            ListView_HitTest(hwnd, &lvhti);

            ClientToScreen(hwnd, &pt);  // WM_NCHITTEST takes screen coordinates

            UINT hittest = SendMessage(hwnd, WM_NCHITTEST, 0, MAKELPARAM(pt.x, pt.y));


            if (hittest == HTVSCROLL)  // my try to do the default behavior
            {
                SendMessage(hwnd, WM_NCLBUTTONDOWN, (WPARAM)hittest, (LPARAM)POINTTOPOINTS(pt));
                //SendMessage(hwnd, WM_NCMOUSEMOVE, (WPARAM)hittest, (LPARAM)POINTTOPOINTS(pt));
            }

        }
    }
        return DefSubclassProc(hwnd, message, wParam, lParam);

    case WM_NCDESTROY:
        ::RemoveWindowSubclass(hwnd, DragAndDrop, 0);
        return DefSubclassProc(hwnd, message, wParam, lParam);
    }
    return ::DefSubclassProc(hwnd, message, wParam, lParam);
}

// main window procedure
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_CREATE:
    {
        g_bDrag = FALSE;  // user is not dragging listview item

        //================ create an example listview
        RECT rec = { 0 };
        GetClientRect(hwnd, &rec);

        HWND hwndLV = CreateWindowEx(0, WC_LISTVIEW,
            L"", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT,
            50, 50, 250, 200, hwnd, (HMENU)2000, hInst, 0);

        // set extended listview styles
        ListView_SetExtendedListViewStyle(hwndLV, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_DOUBLEBUFFER);

        // add some columns
        LVCOLUMN lvc = { 0 };

        lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
        lvc.fmt = LVCFMT_LEFT;

        for (long nIndex = 0; nIndex < 5; nIndex++)
        {
            wchar_t txt[50];
            swprintf_s(txt, 50, L"Column %d", nIndex);

            lvc.iSubItem = nIndex;
            lvc.cx = 60;
            lvc.pszText = txt;

            ListView_InsertColumn(hwndLV, nIndex, &lvc);
        }

        // add some items
        LVITEM lvi;

        lvi.mask = LVIF_TEXT;

        for (lvi.iItem = 0; lvi.iItem < 10000; lvi.iItem++)
        {
            for (long nIndex = 0; nIndex < 5; nIndex++)
            {
                wchar_t txt[50];
                swprintf_s(txt, 50, L"Item %d%d", lvi.iItem, nIndex);

                lvi.iSubItem = nIndex;
                lvi.pszText = txt;
                if (!nIndex)  // item 
                    SendDlgItemMessage(hwnd, 2000, LVM_INSERTITEM, 0, reinterpret_cast<LPARAM>(&lvi));
                else            // sub-item
                    SendDlgItemMessage(hwnd, 2000, LVM_SETITEM, 0, reinterpret_cast<LPARAM>(&lvi));
            }
        }

        //============================ subclass it
        SetWindowSubclass(hwndLV, DragAndDrop, 0, 0);
    }
        return 0L;
    case WM_NOTIFY:
    {
        switch (((LPNMHDR)lParam)->code)
        {
        case LVN_BEGINDRAG:  // user started dragging listview item
        {
            g_bDrag = TRUE;
            SetCapture(((LPNMHDR)lParam)->hwndFrom);  // listview must capture the mouse
        }
            break;
        default:
            break;
        }
    }
        break;
    case WM_CLOSE:
        ::DestroyWindow(hwnd);
        return 0L;
    case WM_DESTROY:
    {
        ::PostQuitMessage(0);
    }
        return 0L;
    default:
        return ::DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

// WinMain

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
    int nCmdShow)
{
    // store hInstance in global variable for later use
    hInst = hInstance;

    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;

    // register main window class
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = 0;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInst;
    wc.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = L"Main_Window";
    wc.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, L"Window Registration Failed!", L"Error!", MB_ICONEXCLAMATION |
            MB_OK);

        return 0;
    }

    // initialize common controls
    INITCOMMONCONTROLSEX iccex;
    iccex.dwSize = sizeof(INITCOMMONCONTROLSEX);
    iccex.dwICC = ICC_LISTVIEW_CLASSES;
    InitCommonControlsEx(&iccex);

    // create main window
    hwnd = CreateWindowEx(0, L"Main_Window", L"Listview Drag and Drop",
        WS_OVERLAPPEDWINDOW,
        50, 50, 400, 400, NULL, NULL, hInstance, 0);

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }

    return Msg.wParam;
}

现在开始拖动一个项目,然后将鼠标移动到滚动条拇指上方/下方/上方 -> 您观察到的行为就是我要寻找的行为。

这个程序有一个缺陷:

当我尝试将项目拖回 ListView 的客户区时,滚动条仍然受到控制,而不是我的拖动代码。这是默认行为,但我需要以这种方式更改它,以便改为执行我的拖动代码。

这是我自己所能做的最好的。您现在可以看到我正在尝试做什么。

如果需要更多信息,我会更新我的帖子。同时,我会继续自己尝试,如果取得进展,我会更新这篇文章。

感谢您的宝贵时间和帮助。最好的问候。

最佳答案

这种方法工作的唯一方法是找到一种方法来在我们滚动时获取 mouse move 消息。鼠标 “丢失” 但捕获仍然保留到 ListView (滚动条)。因此,当鼠标离开滚动区域时,我们需要释放捕获(从滚动条)并将其再次设置为 ListView 。为此,我们将在收到 LVN_BEGINDRAG 通知消息时应用 WH_MOUSE_LL Hook ,并在完成 拖动 时取消 Hook (这是用于垂直滚动条。这个想法与水平完全相同):

HHOOK mouseHook = NULL;
unsigned char g_bDrag = false, g_bScroll = false; //if we are scrolling
unsigned char g_bVsrollExist = false;
RECT scrollRect; //the scrollbar rectangle, in screen coordinates
int thumbTop, thumbBottom; //the y in screen coordinates
int arrowHeight; //the height of the scrollbar up-down arrow buttons

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    NMHDR *nmr;

    switch(message){ //handle the messages

        case WM_NOTIFY:
            nmr = (NMHDR *)lParam;

            if( nmr->code == LVN_BEGINDRAG ){
                //printf("BeginDrag \n");

                g_bDrag = true;
                SetCapture(hwndListView);  // listview must capture the mouse
                if( g_bVsrollExist == true ){
                    mouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)LowLevelMouseProc, NULL, NULL);
                }
            }

        default:   //for messages that we don't deal with
            return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam){
    HWND hwnd;
    MSLLHOOKSTRUCT *mslhs;

    if(nCode == HC_ACTION){
        switch( (int)wParam ){ //handle the messages
            case WM_LBUTTONUP:
                //check if we are dragging and release the mouse and unhook
                if( g_bDrag == true ){
                    g_bDrag = false;
                    g_bScroll = false;

                    hwnd = GetCapture();
                    if( hwnd == hwndListView ){
                        ReleaseCapture();
                    }

                    if( mouseHook != NULL ){UnhookWindowsHookEx(mouseHook); mouseHook = NULL;}
                }

                break;               

            case WM_MOUSEMOVE:
                if( g_bDrag == true ){
                    mslhs = (MSLLHOOKSTRUCT *)lParam;

                    // check if we are outside the area which is: scrollbar area minus the arrow buttons
                    if( mslhs->pt.x < scrollRect.left || mslhs->pt.x >= scrollRect.right ||
                    mslhs->pt.y <= scrollRect.top + arrowHeight + 1 || mslhs->pt.y > scrollRect.bottom - arrowHeight - 1 ){

                        if( g_bScroll == true ){
                            //we need to release the capture from scrollbar
                            ReleaseCapture();

                            //set it again to listview
                            SetTimer(hwndListView, 1, 10, NULL);

                            g_bScroll = false;
                        }
                    }
                }

                break;

            default:   //for messages that we don't deal with
                return CallNextHookEx(NULL, nCode, wParam, lParam);
        }
    }

    return CallNextHookEx(NULL, nCode, wParam, lParam);
}

在子类 ListView 中:

LRESULT CALLBACK ListViewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwrefData){
    POINT pnt;
    SCROLLBARINFO sf;    

    //UNREFERENCED_PARAMETER(uIdSubclass)
    //UNREFERENCED_PARAMETER(dwrefData)

    switch(message){ //handle the messages
        case WM_MOUSEMOVE:
            if( g_bDrag == true && g_bScroll == false && g_bVsrollExist == true ){
                sf.cbSize = sizeof(SCROLLBARINFO);

                GetScrollBarInfo(hwndListView, OBJID_VSCROLL, &sf);

                //in client coordinates
                thumbTop = sf.xyThumbTop;
                thumbBottom = sf.xyThumbBottom;

                //in screen coordinates
                thumbTop += scrollRect.top + 1;
                thumbBottom += scrollRect.top - 2;

                pnt.x = GET_X_LPARAM(lParam);
                pnt.y = GET_Y_LPARAM(lParam);

                ClientToScreen(hwnd, &pnt);

                //we check if we enter the thumb area
                if( pnt.x >= scrollRect.left && pnt.x <= scrollRect.right && 
                    pnt.y > thumbTop + 1 && pnt.y <= thumbBottom - 1 ){
                    g_bScroll = true;
                    SendMessage(hwnd, WM_NCLBUTTONDOWN, (WPARAM)HTVSCROLL, (LPARAM)POINTTOPOINTS(pnt));
                }
            }

            break;

        case WM_TIMER:
            //set the capture to listview to continue getting mouse move messages
            if( (int)wParam == 1 ){
                UpdateWindow(hwndListView);

                SetCapture(hwndListView);

                KillTimer(hwndListView, 1);
            }

            break;

        case WM_LBUTTONDOWN:
            sf.cbSize = sizeof(SCROLLBARINFO);

            GetScrollBarInfo(hwndListView, OBJID_VSCROLL, &sf);

            //check if vertical scrolbar exist
            if( sf.rgstate[0] == STATE_SYSTEM_INVISIBLE ){
                g_bVsrollExist = false;

                break;
            }
            else{g_bVsrollExist = true;}

            arrowHeight = sf.dxyLineButton;
            scrollRect = sf.rcScrollBar;

            //in client coordinates
            thumbTop = sf.xyThumbTop;
            thumbBottom = sf.xyThumbBottom;

            //in screen coordinates
            thumbTop += scrollRect.top + 1;
            thumbBottom += scrollRect.top - 2;

            break;
        case WM_LBUTTONUP:
            if(g_bDrag == true){
                pnt.x = GET_X_LPARAM(lParam);
                pnt.y = GET_Y_LPARAM(lParam);

                g_bDrag = false;
                ReleaseCapture();
            }

            break;

        default:   //for messages that we don't deal with
            return DefSubclassProc(hwnd, message, wParam, lParam);
    }

    return DefSubclassProc(hwnd, message, wParam, lParam);
}

编辑(默认滚动)

unsigned char scrollUp = false, scrollDown = false, scrollLeft = false, 
    scrollRight = false, scrolling = false, vertScrollIsVisible = false, 
    horzScrollIsVisible = false;
int top, down, left, right; //client window in screen coordinates

LRESULT CALLBACK ListViewWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwrefData){
    POINT pnt;
    SCROLLBARINFO sbiVert, sbiHorz;    

    //UNREFERENCED_PARAMETER(uIdSubclass)
    //UNREFERENCED_PARAMETER(dwrefData)

    switch(message){ //handle the messages
        case WM_MOUSEMOVE:
            pnt.x = GET_X_LPARAM(lParam);
            pnt.y = GET_Y_LPARAM(lParam);

            ClientToScreen(hwnd, &pnt);

            if( g_bDrag == true && (horzScrollIsVisible == true || vertScrollIsVisible == true) ){
                CheckMouse(pnt);
            }

            break;

        case WM_LBUTTONDOWN:
            sbiVert.cbSize = sizeof(SCROLLBARINFO);
            sbiHorz.cbSize = sizeof(SCROLLBARINFO);

            GetScrollBarInfo(hwndListView, OBJID_VSCROLL, &sbiVert);
            GetScrollBarInfo(hwndListView, OBJID_HSCROLL, &sbiHorz);

            if( sbiVert.rgstate[0] == STATE_SYSTEM_INVISIBLE ){
                vertScrollIsVisible = false;
            }
            else{
                vertScrollIsVisible = true;
            }

            if( sbiHorz.rgstate[0] == STATE_SYSTEM_INVISIBLE ){
                horzScrollIsVisible = false;
            }
            else{
                horzScrollIsVisible = true;
            }

            if( vertScrollIsVisible == true ){
                //you can get the header handle with hwndHeader = ListView_GetHeader(hwndListView);
                GetWindowRect(hwndHeader, &rt);

                top = rt.bottom;

                GetWindowRect(hwndListView, &rt);

                if( horzScrollIsVisible == true ){
                    bottom = rt.bottom - sbiHorz.dxyLineButton;
                }
                else{
                    bottom = rt.bottom;
                }
            }

            if( horzScrollIsVisible == true ){
                GetWindowRect(hwndListView, &rt);

                left = rt.left;

                if( vertScrollIsVisible == true ){
                    right = rt.right - sbiVert.dxyLineButton;
                }
                else{
                    right = rt.right;
                }
            }

            break;
        case WM_LBUTTONUP:
            if(g_bDrag == true){
                KillTimer(hwndWin, 1); //hwndWin is your main window
                g_bDrag = false;
                ReleaseCapture();
            }

            break;

        default:   //for messages that we don't deal with
            return DefSubclassProc(hwnd, message, wParam, lParam);
    }

    return DefSubclassProc(hwnd, message, wParam, lParam);
}

void CheckMouse(POINT pnt){
    if( pnt.y < top ){
        scrollUp = true;
        scrollDown = false;
    }
    else if( pnt.y >= bottom ){
        scrollDown = true;
        scrollUp = false;
    }
    else{
        scrollUp = false;
        scrollDown = false;
    }

    if( pnt.x >= right ){
        scrollRight = true;
        scrollLeft = false;
    }
    else if( pnt.x < left ){
        scrollLeft = true;
        scrollRight = false;
    }
    else{
        scrollRight = false;
        scrollLeft = false;
    }

    if( scrollUp == true || scrollDown == true || scrollLeft == true || scrollRight == true ){
        if( scrolling == false ){
            scrolling = true;

            SetTimer(hwndWin, 1, 20, NULL);
        }
    }
    else{
        if( scrolling == true ){
            scrolling = false;

            KillTimer(hwndWin, 1);
        }
    }

    return;
}

LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
    NMHDR *nmr;

    switch(message){ //handle the messages

        case WM_NOTIFY:
            nmr = (NMHDR *)lParam;

            if( nmr->code == LVN_BEGINDRAG ){
                //printf("BeginDrag \n");

                g_bDrag = true;
                SetCapture(hwndListView);  // listview must capture the mouse
            }

            break;

        case WM_TIMER:
            if( (int)wParam == 1 ){
                if( scrollUp == true && vertScrollIsVisible == true ){
                    SendMessage(hwndListView, WM_VSCROLL, (WPARAM)0x00000000, (LPARAM)0x0); //up
                }

                if( scrollDown == true && vertScrollIsVisible ){
                    SendMessage(hwndListView, WM_VSCROLL, (WPARAM)0x00000001, (LPARAM)0x0); //down
                }

                if( scrollRight == true && horzScrollIsVisible ){
                    SendMessage(hwndListView, WM_HSCROLL, (WPARAM)0x00000001, (LPARAM)0x0); //right
                }

                if( scrollLeft == true && horzScrollIsVisible  ){
                    SendMessage(hwndListView, WM_HSCROLL, (WPARAM)0x00000000, (LPARAM)0x0); //left
                }
            }

            break;

        default:   //for messages that we don't deal with
            return DefWindowProc(hwnd, message, wParam, lParam);
    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}

关于c++ - 当用户将 ListView 项目拖到其滚动条上时,执行默认滚动行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29681409/

有关c++ - 当用户将 ListView 项目拖到其滚动条上时,执行默认滚动行为的更多相关文章

  1. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  2. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  3. ruby-on-rails - 简单的 Ruby on Rails 问题——如何将评论附加到用户和文章? - 2

    我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。

  4. ruby - RVM "ERROR: Unable to checkout branch ."单用户 - 2

    我在新的Debian6VirtualBoxVM上安装RVM时遇到问题。我已经安装了所有需要的包并使用下载了安装脚本(curl-shttps://rvm.beginrescueend.com/install/rvm)>rvm,但以单个用户身份运行时bashrvm我收到以下错误消息:ERROR:Unabletocheckoutbranch.安装在这里停止,并且(据我所知)没有安装RVM的任何文件。如果我以root身份运行脚本(对于多用户安装),我会收到另一条消息:Successfullycheckedoutbranch''安装程序继续并指示成功,但未添加.rvm目录,甚至在修改我的.bas

  5. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  6. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  7. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  9. ruby - HTTP 请求中的用户代理,Ruby - 2

    我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

  10. ruby-on-rails - capybara poltergeist - 覆盖用户代理 - 2

    有人知道如何将capybarapoltergeist的用户代理覆盖到移动用户代理以进行测试吗?我发现了一些有关为seleniumwebdriver配置它的信息:http://blog.plataformatec.com.br/2011/03/configuring-user-agents-with-capybara-selenium-webdriver/这在capybara闹鬼中怎么可能? 最佳答案 请参阅poltergeistgithub页面上的链接:https://github.com/teampoltergeist/polte

随机推荐