TabControl 选项卡上的控件已禁用

control on TabControl tab is disabled

提问人:Michaelinscarbororough 提问时间:11/13/2023 最后编辑:Michaelinscarbororough 更新时间:11/15/2023 访问量:121

问:

更新-3这是解决方案:Minxin Yu 建议用指向“CMFCTabCtrl m_wndTab”控件的指针替换,而不是使用对窗体视图的引用。谢谢。对于代码,请比较我提供的答案。

Update-2:似乎所有 4 个标签页都删除了对话框标签页的标题栏。我在 InitialUpdaye 中使用的代码是:

m_wnd1.ModifyStyle(WS_CAPTION, 0);
m_wnd2.ModifyStyle(WS_CAPTION, 0);
m_wnd3.ModifyStyle(WS_CAPTION, 0);
m_wnd4.ModifyStyle(WS_CAPTION, 0);

Update-1:请注意,删除标题的代码位于 TabControlView 的 oninitialupdate 中.cpp,实现列表控件的代码位于 CPPL_4(.h 文件和 .cpp 文件中)。最后同样重要的是:请从下方提供的链接下载代码:https://github.com/microsoft/VCSamples/blob/master/VC2010Samples/MFC/Visual%20C%2B%2B%202008%20Feature%20Pack/TabControl/TabControlView.cpp。 谢谢。


我想实现以下目标:

有一个选项卡控件 (CTabCtrl),并在选项卡控件的每个选项卡上添加 1 个列表控件 (CListCtrl)。 列表控件通过数据库填充(1 个列表控件对应 1 个表)。在列表控件下,列是具有列表控件列宽度的编辑控件。这些是用于编辑列表控件的字段。

编辑控件下有一些操作按钮(包括删除、更新和添加记录集(列表控件中的行)以及向上/向下移动一行、上/下移动一页等。

由于这是我使用选项卡控件的第一个项目,因此我使用了此处的一些 MS 代码:

https://github.com/microsoft/VCSamples/blob/master/VC2010Samples/MFC/Visual%20C%2B%2B%202008%20Feature%20Pack/TabControl/TabControlView.cpp

该解决方案很旧,在使用它时,Visual Studio 会将其转换为其 Visual Studio 解决方案的最新版本。代码正在工作。此示例程序的作者将“编辑”控件与选项卡控件一起使用,这意味着每个选项卡页都是一个编辑控件。操作记录发生在列表框中,通过按钮对选项卡控件进行视觉更改。

我更改了代码,以便选项卡页不是使用编辑控件,而是对话框(我使用了 CDialogEx)。

当我发现标题栏令人不安时,我在视图的 oninitialupdate 事件中使用程序代码将其删除。只要我没有将列表控件添加到标签页,这就可以工作。一旦我这样做了,标题就不是“可删除的”。列表控件位于选项卡 4 上。附上图像。

在第二个标签页标签二上,我添加了一个复选框。

这两个控件都无法访问(即我无法选中/取消选中复选框,当我尝试单击列表控件中的一行时没有显示任何选择,CCP_4.cpp文件末尾有一个单击事件代码,该代码永远不会到达(即书签永远不会停止执行!

我的目标是选项卡页 2 和 4 上的列表控件和复选框是可访问的,并且选项卡 4 中的标题栏应该消失,就像其他 3 个选项卡页一样。请帮忙。

我做了什么:

我使用了四个属性页(大)作为我的“对话框”。然后,我为每个对话框创建了类。对于第四个类(选项卡 4 的对话框),我添加了一个虚拟函数“OnInitialUpdate”,并在其中添加了列表控件代码。(请比较第三张图片。它包含对“添加资源”对话框以及“资源”对话框的说明,该对话框显示程序使用的对话框资源)

所有其他 4 个职业都是由 wizzard 类产生的。

这是选项卡四 - 一个列表控件

这是选项卡二 - 一个复选框

这是我创建其他对话框和创建类的地方

图像控制是这里唯一需要的控制!

以下是选项卡 4(类 CPPL_4)的代码,即 cpp 文件:

// CPPL_4.cpp : implementation file
//

#include "pch.h"
#include "stdafx.h"
#include "TabControl.h"
#include "afxdialogex.h"
#include "CPPL_4.h"


// CPPL_4 dialog

IMPLEMENT_DYNAMIC(CPPL_4, CDialogEx)

CPPL_4::CPPL_4(CWnd* pParent /*=nullptr*/)
: CDialogEx(IDD_PPL_4, pParent)
{
}

CPPL_4::~CPPL_4()
{
}

void CPPL_4::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
//DDX_Control(pDX, IDC_COLOR, m_list);
DDX_Control(pDX, IDC_LIST, m_list);
}


BEGIN_MESSAGE_MAP(CPPL_4, CDialogEx)
    ON_WM_ACTIVATE()
    ON_NOTIFY(NM_CLICK, IDC_LIST, &CPPL_4::OnClickList)
END_MESSAGE_MAP()


// CPPL_4 message handlers



BOOL CPPL_4::OnInitDialog()
{
    CDialogEx::OnInitDialog();

    m_list.InsertColumn(0, _T("Column 1"));
    m_list.InsertColumn(1, _T("Column 2"));
    m_list.SetColumnWidth(0, 200);
    m_list.SetColumnWidth(1, 200);
    m_list.InsertItem(0, _T("   1  "));
    m_list.InsertItem(1, _T("   2  "));
    m_list.SetItemText(0, 1, "11");
    m_list.SetItemText(1, 1, "22");

    return FALSE;  // return TRUE unless you set the focus to a control
    // EXCEPTION: OCX Property Pages should return FALSE
}


void CPPL_4::OnClickList(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: Add your control notification handler code here
m_list.SetFocus();
MessageBox("Got click event on list control!");
*pResult = 0;
}

下面是选项卡 4(类 CPPL_4)的代码,即 .h 文件:

#pragma once
#include "afxdialogex.h"


// CPPL_4 dialog

class CPPL_4 : public CDialogEx
{
DECLARE_DYNAMIC(CPPL_4)

public:
    CPPL_4(CWnd* pParent = nullptr);   // standard constructor
    virtual ~CPPL_4();

// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_PPL_4 };
#endif

protected:
// DDX/DDV support
virtual void DoDataExchange(CDataExchange* pDX);    
    DECLARE_MESSAGE_MAP()
public:
    CListCtrl m_list;
    virtual BOOL OnInitDialog();
    afx_msg void OnClickList(NMHDR* pNMHDR, LRESULT* pResult);
};

其他 3 个选项卡的所有内容都相同,但虚拟 OnInitDialog 函数除外

这是我更新为最小骨架的表单视图文件;它应该概述我的问题:

    #include "stdafx.h"
    #include "TabControl.h"

    #include "TabControlDoc.h"
    #include "TabControlView.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////
    // CTabControlView

    IMPLEMENT_DYNCREATE(CTabControlView, CFormView)

    BEGIN_MESSAGE_MAP(CTabControlView, CFormView)
        ON_WM_CONTEXTMENU()
    END_MESSAGE_MAP()

    /////////////////////////////////////////////////////////////
    // CTabControlView construction/destruction

    CTabControlView::CTabControlView()
        : CFormView(CTabControlView::IDD)
    {
    }

    CTabControlView::~CTabControlView()
    {
    }

    void CTabControlView::DoDataExchange(CDataExchange* pDX)
        {
        CFormView::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_TAB, m_wndTabLoc);
        //DDX_Control(pDX, IDC_STATIC_TABLOC, m_wndTabLoc);
    }

    BOOL CTabControlView::PreCreateWindow(CREATESTRUCT& cs)
    {
        // TODO: Modify the Window class or styles here by 
        // modifying the CREATESTRUCT cs

        return CFormView::PreCreateWindow(cs);
    }

    void CTabControlView::OnInitialUpdate()
    {
        // There is only one view ever, so it only needs to do 
        // the initial update once--otherwise the application is  
        // resized needlessly.
        static BOOL bUpdatedOnce = FALSE;
        if (bUpdatedOnce)
            return;
        bUpdatedOnce = TRUE;

        CFormView::OnInitialUpdate();
        GetParentFrame()->RecalcLayout();

        if (m_wndTab.GetSafeHwnd () != NULL)
        {
            return;
        }

        CRect rectTab;

        m_wndTabLoc.GetWindowRect (&rectTab);
        ScreenToClient (&rectTab);

        m_wndTab.Create (CMFCTabCtrl::STYLE_3D, rectTab, this, 1,
            CMFCTabCtrl::LOCATION_TOP);

        m_wnd1.Create(IDD_PPL_1, this);
        // remove title bar of dialog
        m_wnd1.ModifyStyle(WS_CAPTION, 0);

        m_wnd2.Create(IDD_PPL_2, this);         
       // remove title bar of dialog
        m_wnd2.ModifyStyle(WS_CAPTION, 0);

        m_wnd3.Create(IDD_PPL_3, this); 
        // remove title bar of dialog
        m_wnd3.ModifyStyle(WS_CAPTION, 0);

        m_wnd4.Create(IDD_PPL_4, this);
        // remove title bar of dialog
        // This did not work out!!!!
        m_wnd4.m_list.ModifyStyle(WS_CAPTION, 0);

        m_wndTab.AddTab (&m_wnd1, _T("One"), 0, FALSE);
        m_wndTab.AddTab (&m_wnd2, _T("Two"), 1, FALSE);
        m_wndTab.AddTab (&m_wnd3, _T("Three"), 2, FALSE);
        m_wndTab.AddTab (&m_wnd4, _T("Four"), 3, FALSE);

        UpdateData (FALSE);
    }

    /////////////////////////////////////////////////////////////
    // CTabControlView diagnostics

    #ifdef _DEBUG
    void CTabControlView::AssertValid() const
    {
        CFormView::AssertValid();
    }

    void CTabControlView::Dump(CDumpContext& dc) const
    {
        CFormView::Dump(dc);
    }

    CTabControlDoc* CTabControlView::GetDocument() // non-debug version is inline
    {
        ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTabControlDoc)));
        return (CTabControlDoc*)m_pDocument;
    }
    #endif //_DEBUG

    /////////////////////////////////////////////////////////////
    // CTabControlView message handlers

    void CTabControlView::OnContextMenu(CWnd*, CPoint point)
    {
        theApp.ShowPopupMenu (IDR_CONTEXT_MENU, point, this);
    }

更新了 TabControlView.h

    #pragma once
    #include "CPPL_1.h"
    #include "CPPL_2.h"
    #include "CPPL_3.h"
    #include "CPPL_4.h"
    class CTabControlView : public CFormView
    {
    protected: // create from serialization only
        CTabControlView();
        DECLARE_DYNCREATE(CTabControlView)

    public:
        enum { IDD = IDD_TABCONTROL_FORM };

    // Attributes
    public:
        CTabControlDoc* GetDocument();

    protected:
        CMFCTabCtrl m_wndTab;

    // Operations
    public:
        CPPL_1 m_wnd1;
        CPPL_2 m_wnd2;
        CPPL_3 m_wnd3;
        CPPL_4 m_wnd4;
        // Overrides
        public:
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
        virtual void OnInitialUpdate(); // called first time after construct

    // Implementation
    public:
        virtual ~CTabControlView();
    #ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
    #endif

    protected:
        //void AddNotification (LPCTSTR lpszText);

    protected:
        afx_msg void OnContextMenu(CWnd*, CPoint point);

        DECLARE_MESSAGE_MAP()
    public:
        //afx_msg void OnCbnSelchangeTabStyle();
        //afx_msg void OnStnClickedTab();
        CStatic m_wndTabLoc;
    };

    #ifndef _DEBUG  // debug version in TabControlView.cpp
    inline CTabControlDoc* CTabControlView::GetDocument()
       { return (CTabControlDoc*)m_pDocument; }
    #endif

更新的 TabControlView.h 文件结束

C++ Visual-Studio 选项卡 MFC

评论

0赞 Jesper Juhl 11/13/2023
您需要阅读最小的可重复示例
0赞 Jesper Juhl 11/13/2023
“再次对不起。它很长“——问题不在于代码本身的长度,而在于它不是演示问题的最小示例。如果你阅读了最小的可重现示例,你就会发现,练习的重点是创建一个新的最小程序,它只包含足以演示问题的程序,仅包含更多内容。是的,创建这样的程序需要努力,但这就是这里所期望的。我们不想猜测或费力地浏览堆积如山的代码来为您找出问题所在 - 您必须完成这项工作。
0赞 Michaelinscarbororough 11/13/2023
嗨,Jesper,我在 OninitialUpdate 虚拟函数中添加了一些文档,我认为这应该有助于理解代码“只是不起作用”。好的,我将删除所有事件,对于我的问题来说不是必需的。
0赞 Jesper Juhl 11/13/2023
什么是调试器,它如何帮助我诊断问题?应该是有用的阅读。
0赞 Michaelinscarbororough 11/13/2023
嗨,Jesper,我在开发过程中严重依赖调试器,感谢您的提示。.我删除了上面的大部分讨论,并相应地更改了我的代码。我希望这是令人满意的。

答:

0赞 Michaelinscarbororough 11/15/2023 #1

我想让你知道,俞敏欣想出了答案,我只想结束我的问题,因为我得到了我一开始要求的一切:

为什么有一个带有标题栏的选项卡式对话框页面,尽管标题栏样式 (WS_CAPTIOM) 已被删除:

有效的代码是:

         m_wnd4.ModifyStyle(WS_CAPTION, 0);

其中 m_wnd4 是 CPPL_4 类型(请进一步比较代码)

为什么我无法访问选项卡式对话框中的控件?

这是俞敏欣的建议:

m_wnd1。创建(IDD_PPL_1, &m_wndTab);

其中原始代码有:

m_wnd1。创建(IDD_PPL_1,这个);

“this”是指向表单视图的指针,并且 &m_wndTab 是指向 MFCTabCtrl 类型的选项卡控件的指针。

请进一步查看完整代码!

感谢所有帮助过的人!!!

以下是代码,它实际上留下了一个悬而未决的问题,即: 为什么我必须从示例项目中复制控件才能获得选项卡式运行时控件。

    void CTabControlView::OnInitialUpdate()
    {
        // There is only one view ever, so it only needs to do the initial
        // update once--otherwise the application is  resized needlessly.
        static BOOL bUpdatedOnce = FALSE;
        if (bUpdatedOnce)
            return;
        bUpdatedOnce = TRUE;

        CFormView::OnInitialUpdate();
        GetParentFrame()->RecalcLayout();

        if (m_wndTab.GetSafeHwnd () != NULL)
            return;

        CRect rectTab;

        m_wndTabLoc.GetWindowRect (&rectTab);
        ScreenToClient (&rectTab);

        m_wndTab.Create (CMFCTabCtrl::STYLE_3D, rectTab, this, 1, CMFCTabCtrl::LOCATION_TOP);
        // MinXin Wu suggested to replace "this" by "&m_wndTab"
        m_wnd1.Create(IDD_PPL_1, &m_wndTab); 

        // remove title bar of dialog
        m_wnd1.ModifyStyle(WS_CAPTION, 0);

        // MinXin Wu suggested to replace "this" by "&m_wndTab"
        m_wnd2.Create(IDD_PPL_2, &m_wndTab);
        // remove title bar of dialog
        m_wnd2.ModifyStyle(WS_CAPTION, 0);

        // MinXin Wu suggested to replace "this" by "&m_wndTab"
        m_wnd3.Create(IDD_PPL_3, &m_wndTab);

        // remove title bar of dialog
        m_wnd3.ModifyStyle(WS_CAPTION, 0);

        // MinXin Wu suggested to replace "this" by "&m_wndTab"
        m_wnd4.Create(IDD_PPL_4, &m_wndTab);

        // remove title bar of dialog
        m_wnd4.ModifyStyle(WS_CAPTION, 0);


        m_wndTab.AddTab (&m_wnd1, _T("One"), 0, FALSE);
        m_wndTab.AddTab (&m_wnd2, _T("Two"), 1, FALSE);
        m_wndTab.AddTab (&m_wnd3, _T("Three"), 2, FALSE);
        m_wndTab.AddTab (&m_wnd4, _T("Four"), 3, FALSE);
        UpdateData (FALSE);
        }

CPPL_1 - CPPL_4类可以在问题中找到 这是表单视图的头文件!

    // This is a part of the Microsoft Foundation Classes C++ library.
    // Copyright (C) Microsoft Corporation
    // All rights reserved.
    //
    // This source code is only intended as a supplement to the
    // Microsoft Foundation Classes Reference and related
    // electronic documentation provided with the library.
    // See these sources for detailed information regarding the
    // Microsoft Foundation Classes product.

    #pragma once
    #include "CPPL_1.h"
    #include "CPPL_2.h"
    #include "CPPL_3.h"
    #include "CPPL_4.h"
    class CTabControlView : public CFormView
    {
    protected: // create from serialization only
        CTabControlView();
        DECLARE_DYNCREATE(CTabControlView)

    public:
        enum { IDD = IDD_TABCONTROL_FORM };

    // Attributes
    public:
        CTabControlDoc* GetDocument();

    protected:
        CMFCTabCtrl m_wndTab;

    // Operations
    public:
        CPPL_1 m_wnd1;
        CPPL_2 m_wnd2;
        CPPL_3 m_wnd3;
        CPPL_4 m_wnd4;
        // Overrides
        public:
        virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
        protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
        virtual void OnInitialUpdate(); // called first time after construct

    // Implementation
    public:
        virtual ~CTabControlView();
    #ifdef _DEBUG
        virtual void AssertValid() const;
        virtual void Dump(CDumpContext& dc) const;
    #endif

    protected:
        //void AddNotification (LPCTSTR lpszText);

    protected:
        afx_msg void OnContextMenu(CWnd*, CPoint point);

        DECLARE_MESSAGE_MAP()
    public:
        //afx_msg void OnCbnSelchangeTabStyle();
        //afx_msg void OnStnClickedTab();
        CStatic m_wndTabLoc;
        afx_msg void OnStnClickedTab();
        afx_msg void OnBnClickedButton1();
    };

    #ifndef _DEBUG  // debug version in TabControlView.cpp
    inline CTabControlDoc* CTabControlView::GetDocument()
       { return (CTabControlDoc*)m_pDocument; }
    #endif

评论

0赞 Minxin Yu - MSFT 11/16/2023
很高兴知道这个建议对你有用。您可以单击“✔”接受答案。它还将帮助其他人解决类似的问题。