如何實現由列表控件控制的屬性表

(本文發表於VCKBase,可從如下鏈接獲取源代碼:http://www.vckbase.com/code/downcode.asp?id=3110歡迎討論)

      很多MFC程序都用到了屬性表和屬性頁來實現選項設置的界面,但是MFC本身提供的屬性表頁功能有限,一些新軟件都實現了自己定義的屬性頁。MFC原始的屬性頁是通過CTabCtrl進行切換控制的,這裏給出了一種現在較爲常見的用CListCtrl進行頁面切換的屬性頁的方法,並且對對列表控件進行了重繪。 CMyPropertySheet是一個從CPropertySheet派生而來的類,因此仍然可以使用MFC CPropertySheet的諸多特性,具體使用方法稍後我會詳細說明。

該屬性表的實現效果如下: 

一、使用


CMyPropertySheet的使用方法與MFC的CPropertySheet類似,首先要在程序中創建兩個屬性頁,也就是兩個CPropertyPage的派生對象。然後將MyPropertySheet.cpp 和 MyPropertySheet.h添加至工程,在程序的視圖類頭文件中(假定是個SDI程序)將CMyPropertySheet的頭文件包含進來

#include “MyPropertySheet.h”

在資源視圖裏設置一個新的菜單項“選項”(放在哪兒隨你) 用ClassWizard添加響應函數,在該函數裏添加如下代碼創建一個屬性表對象myPS

CMyPropertySheet myPS;

然後向屬性表添加兩個屬性頁。

myPS.AddPage(&m_page1);
myPS.AddPage(&m_page2);

接下來要添加屬性頁的圖標,該圖標會在對應列表項以及屬性頁的標題上顯示,注意這裏添加的順序要與屬性頁的添加順序保持一致。

myPS.AddIcon(IDI_GLOBAL);      
myPS.AddIcon(IDI_ADDITION);

最後創建並顯示該屬性頁。

myPS.DoModal();

剩下的工作就跟一般屬性表完全一樣了。

CMyPropertySheet類提供如下自定義函數,可以對屬性表的外觀進行設置。

SetSepratorColor,SetCaptionColor與SetSelectedColor都接受一個類型爲COLORREF的參數,分別用以設置列表分隔線,屬性頁標題以及列表選擇項背景的顏色。

SetListFont設置列表的字體。

讀者也可以根據自己的需要對其進行擴充。

二、實現邏輯

MFC原來的屬性頁是由TabCtrl控制的,而且屬性頁的大小已經與屬性表按比例設置好,因此,要實現如圖一所示的屬性頁,我們有如下幾步工作需要做:

1. 對屬性頁原來的TabCtrl進行隱藏。
2. 調整屬性表的大小,將屬性頁移至屬性表右側,以容納列表控件。
3. 獲得TabCtrl的矩形,根據該矩形畫屬性頁標題。
4. 初始化列表控件內容,調整列表項高度。
5. 響應列表的NM_CLICK事件,根據得到的點擊項ID進行屬性頁的切換。

其中調整尺寸的工作必須在OnInitDialog函數中進行。

BOOL CMyPropertySheet::OnInitDialog()
{
	
	BOOL bResult = CPropertySheet::OnInitDialog();	
 
	//計算屬性頁的矩形,擴大屬性表並將屬性頁其移至右側
	CRect rect, rectPage, rectTab;
	GetPage(0)->GetWindowRect(&rectPage);
	
	GetWindowRect(&rect);
	rect.right += 150;
	
    int nWidth = rectPage.Width();
	rectPage.right = rect.right - 20; 
	rectPage.left = rect.right - nWidth;
	ScreenToClient(&rectPage);
	m_rectPage = rectPage;
	MoveWindow(&rect);
	GetPage(0)->MoveWindow(&rectPage);
    
	//隱藏屬性頁原來的TabControl
	CTabCtrl *pTab = GetTabControl() ;
	pTab->GetWindowRect(&rectTab);
	ScreenToClient(&rectTab);
	if(!pTab->ShowWindow(SW_HIDE))
		return FALSE;	
   
	//創建列表控件並用一個CImageList對象與之關聯
	if(!m_wndList.Create(WS_CHILD | WS_VISIBLE |  LVS_REPORT | LVS_NOCOLUMNHEADER , CRect(10 ,rectTab.top,150,rectPage.bottom ),this,0xFFFF))
		return FALSE;
	m_wndList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
	m_wndList.SetImageList(&m_imgList, LVSIL_SMALL);
	
	InitList();

	//設置行高度
	CFont font;
	font.CreatePointFont(240,_T("宋體"));
	m_wndList.SetFont(&font);
	
	CString strCaption;
	GetPage(0)->GetWindowText(strCaption);	
	_tcscpy(m_szCaption, strCaption.GetBuffer(strCaption.GetLength()));	

	return bResult;
}


屬性頁的切換:

void CMyPropertySheet::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE lpItem = reinterpret_cast(pNMHDR);
	m_nSelectedItem = lpItem->iItem ;

   if (lpItem->iItem  >= 0 && lpItem->iItem < m_wndList.GetItemCount())
   {
	   m_nSelectedItem = lpItem->iItem;
	   CString strCaption = m_wndList.GetItemText(lpItem->iItem,0);
	  _tcscpy(m_szCaption, strCaption);	

	SetActivePage(m_nSelectedItem);
	
	Invalidate();	
	
	GetPage(m_nSelectedItem)->MoveWindow(&m_rectPage);

	m_wndList.SetFocus();
   }
	
	
}

三、總結

關於列表控件自繪的問題在這裏不做詳細討論,可以參考源代碼裏面OnNMCustomDraw的部分以及MSDN上的相關資料。對屬性頁的修改還有很多種方法和很多種方式,比如還可以用樹型控件進行控制,這裏提供的方法也可以做一般意義上的推廣 ,並不難實現其它方式的控制。程序在Visual C++ 2005 下編譯通過。

 四、源碼

MyPropertySheet.h

 


#ifndef MYPROPERTYSHEET_H
#define MYPROPERTYSHEET_H

#pragma once

#pragma warning(disable : 4996)



// CMyPropertySheet

class CMyPropertySheet : public CPropertySheet
{
    DECLARE_DYNAMIC(CMyPropertySheet)
private:
    
void InitList(void);
    
void DrawCaption(CDC * pDC, const COLORREF clrCaption);
    
void DrawGradientLine(CDC* pDC, COLORREF clrLine, POINT ptStart, POINT ptEnd);

public:
    CMyPropertySheet(UINT nIDCaption, CWnd
* pParentWnd = NULL, UINT iSelectPage = 0);
    CMyPropertySheet(LPCTSTR pszCaption, CWnd
* pParentWnd = NULL, UINT iSelectPage = 0);
    
virtual ~CMyPropertySheet();

protected:
    CImageList m_imgList;
    CListCtrl m_wndList;
    
int  m_nSelectedItem;
    
//列表的字體,大小不能超過列表項的高度
    CFont m_ftList;
    
    COLORREF m_clrTextBkSele ;
    COLORREF m_clrSeprator;
    COLORREF m_clrCaption;
    COLORREF m_clrSelected;

    LPTSTR m_szCaption;
    CRect m_rectPage;

    DECLARE_MESSAGE_MAP()
public:
    
virtual BOOL OnInitDialog();

    afx_msg 
void OnPaint();
    afx_msg 
void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg 
void OnNMCustomDraw(NMHDR *pNMHDR, LRESULT *pResult);    

    
int AddIcon(HICON icon);
    
//設置屬性頁標題的初始顏色
    void SetCaptionColor(const COLORREF clrCaption);
    
//設置列表控件分隔線的初始顏色
    void SetSepratorColor(const COLORREF clrSeprator);
    
//設置列表控件某項被選擇時的背景色
    void SetSelectedColor(const COLORREF clrSelected);

    
//設置列表控件字體
    void SetListFont(CFont * pFont);

    
}
;


#endif

 

MyPropertySheet.cpp

 

// MyPropertySheet.cpp : 實現文件
//

#include 
"stdafx.h"

#include 
"MyPropertySheet.h"




IMPLEMENT_DYNAMIC(CMyPropertySheet, CPropertySheet)

CMyPropertySheet::CMyPropertySheet(UINT nIDCaption, CWnd
* pParentWnd, UINT iSelectPage)
    :CPropertySheet(nIDCaption, pParentWnd, iSelectPage), m_nSelectedItem(
0), m_clrTextBkSele(RGB(0,132,255)),m_clrSeprator(RGB(0,132,255)),
    m_clrCaption(RGB(
92,132,255))
{
    m_szCaption 
= new TCHAR[128];
        

    
//默認16*16,32位色圖標
    m_imgList.Create(16,16,ILC_COLOR32, 020);

    m_ftList.CreatePointFont(
90,_T("宋體"));

}


CMyPropertySheet::CMyPropertySheet(LPCTSTR pszCaption, CWnd
* pParentWnd, UINT iSelectPage)
    :CPropertySheet(pszCaption, pParentWnd, iSelectPage), m_nSelectedItem(
0), m_clrTextBkSele(RGB(0,132,255)),m_clrSeprator(RGB(0,132,255)),
    m_clrCaption(RGB(
92,132,255))
{
    m_szCaption 
= new TCHAR[128];

    m_imgList.Create(
16,16,ILC_COLOR32, 020);
    m_ftList.CreatePointFont(
90,_T("宋體"));

}


CMyPropertySheet::
~CMyPropertySheet()
{

    delete [] m_szCaption;
    
}



BEGIN_MESSAGE_MAP(CMyPropertySheet, CPropertySheet)
    ON_WM_PAINT()
    ON_NOTIFY(NM_CLICK, 
0xFFFF, OnNMClick)
    ON_NOTIFY(NM_CUSTOMDRAW,
0xFFFF, OnNMCustomDraw)
    
END_MESSAGE_MAP()


// CMyPropertySheet 消息處理程序

BOOL CMyPropertySheet::OnInitDialog()
{
    
    BOOL bResult 
= CPropertySheet::OnInitDialog();    
 
    
//計算屬性頁的矩形,擴大屬性表並將屬性頁其移至右側
    CRect rect, rectPage, rectTab;
    GetPage(
0)->GetWindowRect(&rectPage);
    
    GetWindowRect(
&rect);
    rect.right 
+= 150;
    
    
int nWidth = rectPage.Width();
    rectPage.right 
= rect.right - 20
    rectPage.left 
= rect.right - nWidth;
    ScreenToClient(
&rectPage);
    m_rectPage 
= rectPage;
    MoveWindow(
&rect);
    GetPage(
0)->MoveWindow(&rectPage);
    
    
//隱藏屬性頁原來的TabControl
    CTabCtrl *pTab = GetTabControl() ;
    pTab
->GetWindowRect(&rectTab);
    ScreenToClient(
&rectTab);
    
if(!pTab->ShowWindow(SW_HIDE))
        
return FALSE;

    
    
   
    
//創建列表控件並用一個CImageList對象與之關聯
    if(!m_wndList.Create(WS_CHILD | WS_VISIBLE |  LVS_REPORT | LVS_NOCOLUMNHEADER , CRect(10 ,rectTab.top,150,rectPage.bottom ),this,0xFFFF))
        
return FALSE;
    m_wndList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
    m_wndList.SetImageList(
&m_imgList, LVSIL_SMALL);
    
    InitList();

    
//這一步是爲了擴大行高度
    CFont font;
    font.CreatePointFont(
240,_T("宋體"));
    m_wndList.SetFont(
&font);
    
    CString strCaption;
    GetPage(
0)->GetWindowText(strCaption);    
    _tcscpy(m_szCaption, strCaption.GetBuffer(strCaption.GetLength()));    

    
return bResult;
}


void CMyPropertySheet::OnPaint()
{
    CPaintDC dc(
this); // device context for painting
    CRect rectList,rectPage;
    m_wndList.GetWindowRect(
&rectList);
    GetPage(
0)->GetWindowRect(&rectPage);
    ScreenToClient(
&rectPage);
    ScreenToClient(
&rectList);

    rectList.left 
= rectList.left -1;
    rectList.right 
= rectList.right + 1;
    rectList.top 
= rectList.top - 1;
    rectList.bottom 
= rectList.bottom + 1;

    rectPage.left 
-= 1;
    rectPage.right 
+= 1;
    rectPage.top 
-= 1;
    rectPage.bottom 
+= 1;
    CBrush brush(RGB(
141,141,141));
    dc.FrameRect(
&rectList,&brush);
    dc.FrameRect(
&rectPage, &brush);
    
        
    DrawCaption(
&dc, m_clrCaption);
    
    
    
    
}


void CMyPropertySheet::DrawCaption(CDC * pDC, const COLORREF clrCaption)
{
    CDC dcBuf;
    dcBuf.CreateCompatibleDC(pDC);
    CBitmap bmp;
    
    CRect rectCap, rectList, rectPage,rectSheet;
    m_wndList.GetWindowRect(
&rectList);
    ScreenToClient(
&rectList);
    GetPage(
0)->GetWindowRect(&rectPage);
    ScreenToClient(
&rectPage);

    rectCap 
= rectPage;
    rectCap.top 
= rectList.top -1;
    rectCap.left 
-= 1;
    rectCap.right 
+= 1;
    rectCap.bottom 
=rectPage.top -1 ;


    GetClientRect(
&rectSheet);
    
    rectCap.bottom 
+=1;
    
    
    
    bmp.CreateCompatibleBitmap(pDC, rectCap.right , rectSheet.Height());

    
    dcBuf.SelectObject(bmp);

    
//起始顏色
    int clrBBase = clrCaption>>16 & 0x000000FF;
    
int clrGBase = clrCaption>>8 & 0x000000FF;
    
int clrRBase = clrCaption & 0x000000FF;    

    
//過渡中顏色
    int clrRCurr = clrRBase;
    
int clrGCurr = clrGBase;
    
int clrBCurr = clrBBase;
    
    
//色彩增量
    const double nRClrInc = (double)(255 - clrRBase) / (double)rectCap.Width() ;    
    
const double nGClrInc = (double)(255 - clrGBase) / (double)rectCap.Width() ;
    
const double nBClrInc = (double)(255 - clrBBase) / (double)rectCap.Width() ;



    
//畫漸進色標題

    CRect drawRect 
= rectCap;
    
    
for (int nLeft = rectCap.left, nRight = rectCap.left + 1 ; nLeft < rectCap.right; nLeft ++, nRight ++)
    
{

        drawRect.left 
= nLeft;
        drawRect.right 
= nRight;

        dcBuf.FillSolidRect(
&drawRect, RGB(clrRCurr,clrGCurr,clrBCurr));

        clrRCurr 
= (int)((nLeft - rectCap.left) * nRClrInc + clrRBase);
        clrGCurr 
= (int)((nLeft - rectCap.left) * nGClrInc + clrGBase);
        clrBCurr 
= (int)((nLeft - rectCap.left) * nBClrInc + clrBBase);
        
    }


    

    dcBuf.SetBkMode(TRANSPARENT);
    CFont font;
    

    
   
    font.CreatePointFont(
110,_T("宋體"),pDC);
    dcBuf.SelectObject(
&font);
    

    
    dcBuf.SetTextColor(RGB(
0,0,0));
    dcBuf.TextOut(rectCap.left 
+ 26, rectCap.top +5,m_szCaption, (int)_tcslen(m_szCaption));
    dcBuf.SetTextColor(RGB(
255,255,255));
    dcBuf.TextOut(rectCap.left 
+ 25, rectCap.top + 4, m_szCaption, (int)_tcslen(m_szCaption));

    ::DrawIconEx(dcBuf,rectCap.left 
+ 4, rectCap.top + 3, m_imgList.ExtractIcon(m_nSelectedItem),1616, NULL,NULL, DI_NORMAL);


        
        
        

    pDC
->BitBlt(rectCap.left,rectCap.top,rectCap.Width()+rectCap.Width(),rectCap.Height(),&dcBuf,rectCap.left,rectCap.top,SRCCOPY);
    
}


void CMyPropertySheet::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE lpItem 
= reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    m_nSelectedItem 
= lpItem->iItem ;

   
if (lpItem->iItem  >= 0 && lpItem->iItem < m_wndList.GetItemCount())
   
{
       m_nSelectedItem 
= lpItem->iItem;
       CString strCaption 
= m_wndList.GetItemText(lpItem->iItem,0);
    _tcscpy(m_szCaption, strCaption);
    
    

    SetActivePage(m_nSelectedItem);
    
    Invalidate();
    
    
    GetPage(m_nSelectedItem)
->MoveWindow(&m_rectPage);

    m_wndList.SetFocus();
   }

    
    
}

void CMyPropertySheet::InitList(void)
{
    LVITEM lvi;
    ::ZeroMemory(
&lvi, sizeof(lvi));
    
    
    CHeaderCtrl 
*pHeader = m_wndList.GetHeaderCtrl();
    
    
    pHeader
->ShowWindow(SW_HIDE);

    CRect rectList;
    m_wndList.GetWindowRect(
&rectList);
    ScreenToClient(
&rectList);
    
//報表頭不會顯示,但是是必需的
    m_wndList.InsertColumn(0,_T("設置"), LVCFMT_CENTER, rectList.Width(), 0);
    

    CString strCaption;

    CTabCtrl 
*pTab = GetTabControl();
    TCITEM tci;
    ::ZeroMemory(
&tci,sizeof(tci));
    tci.mask 
= TCIF_TEXT;
    tci.cchTextMax 
= 256;
    TCHAR szBuf[
256= {0};
    tci.pszText 
= szBuf;
    
    
for (int idxPge = 0; idxPge < GetPageCount(); idxPge ++)
    
{
        
if(pTab->GetItem(idxPge, &tci))

        
{
            lvi.iItem 
= idxPge;
            lvi.iSubItem 
= 0;
            lvi.iImage 
= idxPge;
            lvi.mask 
= LVIF_TEXT | LVIF_IMAGE;   
            lvi.pszText 
= tci.pszText ;
            m_wndList.InsertItem(
&lvi);
        }

    }





}


void CMyPropertySheet::OnNMCustomDraw(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMLVCUSTOMDRAW  pLVCD 
= reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);


    CRect rectRow, rectList;

    m_wndList.GetWindowRect(
&rectList);
    ScreenToClient(
&rectList);
    m_wndList.GetItemRect(
0&rectRow, LVIR_BOUNDS);
    
int iItemHeight = rectRow.Height();
    
int iItemTop = rectRow.top ;


    ::SelectObject(pLVCD
->nmcd.hdc, m_ftList);


    
switch (pLVCD->nmcd.dwDrawStage)
    
{


    
case CDDS_PREPAINT:
        
*pResult = CDRF_NOTIFYITEMDRAW;
        
break;
    
case CDDS_ITEMPREPAINT:


        
*pResult = CDRF_NOTIFYSUBITEMDRAW;
        
break;
    
case (CDDS_ITEMPREPAINT | CDDS_SUBITEM):
        
{
            
int iCol = pLVCD->iSubItem ;
            
int iRow = (int)pLVCD->nmcd.dwItemSpec;
            CRect rectItem(pLVCD
->nmcd.rc), rectIcon;

            
//計算每個子項的矩形

            rectItem.top 
= iItemTop + iRow * iItemHeight;
            rectItem.bottom 
= rectItem.top + iItemHeight;

            rectItem.left 
+=3;
            rectItem.right 
-=3;

            
if (iRow == 0)
                rectItem.top 
+=3;
            CDC 
*pDC = CDC::FromHandle(pLVCD->nmcd.hdc);            

            LOGFONT lf;
            ::ZeroMemory(
&lf, sizeof(lf));
            pDC
->GetCurrentFont()->GetLogFont(&lf);


            
//獲得第圖標所在的矩形
            m_wndList.GetSubItemRect(iRow,0, LVIR_ICON, rectIcon);

            
const COLORREF clrBlack = RGB(0,0,0);
            
const COLORREF clrWhite = RGB(255,255,255);

            
if ((pLVCD->nmcd.uItemState & (CDIS_FOCUS | CDIS_SELECTED)) == (CDIS_FOCUS | CDIS_SELECTED))
            
{
                    
                    
                    pDC
->FillSolidRect(&rectItem, m_clrTextBkSele);
                    pDC
->SetTextColor(clrWhite);
                    pDC
->TextOut(rectItem.left + rectIcon.Width() + 8, (iRow == 0?(rectItem.top - 3):rectItem.top) + (iItemHeight - abs(lf.lfHeight))/2, m_wndList.GetItemText(iRow, iCol), (int)_tcslen(m_wndList.GetItemText(iRow, iCol)));
                    
                    ::DrawIconEx(
*pDC,rectIcon.left, rectIcon.top + (iItemHeight - 16/ 2,m_imgList.ExtractIcon(iRow),16,16,NULL,NULL,DI_NORMAL);                        
                    
                    pDC
->SetTextColor(clrBlack);
                    
                    DrawGradientLine(pDC,m_clrSeprator,CPoint(rectItem.left, rectItem.bottom
-1), CPoint(rectItem.right, rectItem.bottom-1));                    

            
            }

            
            
else
            
            
{
                
                    pDC
->FillSolidRect(&rectItem, clrWhite);

                    pDC
->TextOut(rectItem.left + rectIcon.Width() + 8, (iRow == 0?(rectItem.top - 3):rectItem.top) + (iItemHeight - abs(lf.lfHeight))/2, m_wndList.GetItemText(iRow, iCol), (int)_tcslen(m_wndList.GetItemText(iRow, iCol)));

                    ::DrawIconEx(
*pDC,rectIcon.left, rectIcon.top + (iItemHeight - 16/ 2, m_imgList.ExtractIcon(iRow),16,16,NULL,NULL,DI_NORMAL);

                    DrawGradientLine(pDC,m_clrSeprator,CPoint(rectItem.left, rectItem.bottom
-1), CPoint(rectItem.right, rectItem.bottom-1));                    

            

            }

            
            
            
*pResult = CDRF_SKIPDEFAULT;
            
break;
        }



    
default:
        
*pResult = CDRF_SKIPDEFAULT;
        
break;
    }
    



}



void CMyPropertySheet::DrawGradientLine(CDC* pDC, COLORREF clrLine, POINT ptStart, POINT ptEnd)
{
//畫漸近線,從clrLine的顏色變化至白色

    
int clrBBase = clrLine>>16 & 0x000000FF;
    
int clrGBase = clrLine>>8 & 0x000000FF;
    
int clrRBase = clrLine & 0x000000FF;

    
int clrBCurr = 255;
    
int clrGCurr = 255;
    
int clrRCurr = 255;

    
double dRInc = (double)(255 - clrRBase) / (double)(abs(ptEnd.x - ptStart.x));
    
double dGInc = (double)(255 - clrGBase) / (double)(abs(ptEnd.x - ptStart.x));
    
double dBInc = (double)(255 - clrBBase) / (double)(abs(ptEnd.x - ptStart.x));

    POINT ptCurr 
= ptStart;

    
for (;ptCurr.x < ptEnd.x;ptCurr.x ++)            
    
{
        pDC
->SetPixel(ptCurr.x, ptCurr.y -1,RGB(clrRCurr,clrGCurr,clrBCurr));
        pDC
->SetPixel(ptCurr, RGB(clrRCurr,clrGCurr,clrBCurr));
        clrRCurr 
= clrRBase + (int)((ptCurr.x - ptStart.x) * dRInc);
        clrGCurr 
= clrGBase + (int)((ptCurr.x - ptStart.x) * dGInc);
        clrBCurr 
= clrBBase + (int)((ptCurr.x - ptStart.x) * dBInc);
    }

    

    

}


int CMyPropertySheet::AddIcon(HICON icon)
{
    
return m_imgList.Add(icon);
}


void CMyPropertySheet::SetCaptionColor(const COLORREF clrCaption)
{
    m_clrCaption 
= clrCaption;
}


void CMyPropertySheet::SetSepratorColor(const COLORREF clrSeprator)
{
    m_clrSeprator 
= clrSeprator;
}


void CMyPropertySheet::SetListFont(CFont * pFont)
{
    m_ftList.Attach(pFont
->GetSafeHandle());
}


void CMyPropertySheet::SetSelectedColor(const COLORREF clrSelected)
{
    m_clrTextBkSele 
= clrSelected;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章