[WIN]變更程式執行優先順序

如有需要變更執行檔的執行優先順序,可呼叫SetPriorityClass Function()來達成需求。

第一個參數是目前程序的HANDLE,第二個參數則為要設定的順序參數。

目前測試結果是有效~~XDD

[C++]在Class內宣告靜態float常數

一般對compiler而言,要宣告class內的靜態常數,只能宣告成int的形態。

如果要宣告成
 static const float STATIC_FLOAT = 1.F;  

則Compiler會出現「a member of type "const float" cannot have a in-class initializer」

因此,如想要在class內宣告靜態的float,則需先在class內宣告個靜態的float,但不給予值。並在*.cpp給定此常數值即可:

*.h
 class CTestClass  
 {  
  static cosnt float STATIC_FLOAT;  
  ...  
  ...  
 }  

*.cpp
 const flaot CTestClass::STATIC_FLOAT = 1.F;  

參考連結:static const float in C++. why not?

[CListCtrl]欄位顯示多行文字

由於MFC提供的CListCtrl並無輸入多行文字功能,因此也需要從繪圖的部分下手。
由於ClistCtrl一次也只能顯示一行文字,因此在進行顯示多行文字之前,需先讓CListCtrl的欄位可以隨著文字段數變動。這邊可以參考[CListCtrl]改變行高 。(參考文獻在上述連結內都有)

在顯示多行文字部分,則是透過改寫DrawItem()來讓文字可以斷行。

使用前,需先將CListCtrl的Owner Draw Fixed屬性打開(坊間流傳的SetExtendedStyle(LVS_OWNERDRAWFIXED)並無效果)。(PS.在這邊浪費了好幾個小時@@,果然跑不起來還是要先查設定@@)

在.h部分
 afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);  

在.cpp部分
 void CXListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)   
 {  
     TCHAR lpBuffer[256];  
     LV_ITEM lvi;  
     lvi.mask = LVIF_TEXT | LVIF_PARAM ;  
     lvi.iItem = lpDrawItemStruct->itemID ;       
     lvi.iSubItem = 0;  
     lvi.pszText = lpBuffer ;  
     lvi.cchTextMax = sizeof(lpBuffer);  
     VERIFY(GetItem(&lvi));  
     LV_COLUMN lvc, lvcprev ;  
     ::ZeroMemory(&lvc, sizeof(lvc));  
     ::ZeroMemory(&lvcprev, sizeof(lvcprev));  
     lvc.mask = LVCF_WIDTH | LVCF_FMT;  
     lvcprev.mask = LVCF_WIDTH | LVCF_FMT;  
     for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     {  
         if ( nCol > 0 )   
         {  
             // Get Previous Column Width in order to move the next display item  
             GetColumn(nCol-1, &lvcprev) ;  
             lpDrawItemStruct->rcItem.left += lvcprev.cx ;  
             lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left ;      
         }

         // Get the text   
         ::ZeroMemory(&lvi, sizeof(lvi));  
         lvi.iItem = lpDrawItemStruct->itemID;  
         lvi.mask = LVIF_TEXT | LVIF_PARAM;  
         lvi.iSubItem = nCol;  
         lvi.pszText = lpBuffer;  
         lvi.cchTextMax = sizeof(lpBuffer);  
         VERIFY(GetItem(&lvi));  
         CDC* pDC;  
         pDC = CDC::FromHandle(lpDrawItemStruct->hDC);  
 //--------------- Full selection - highlight -----------------------  
         if ( lpDrawItemStruct->itemState & ODS_SELECTED )  
         {  
             pDC->FillSolidRect(&lpDrawItemStruct->rcItem, GetSysColor(COLOR_HIGHLIGHT)) ;   
             pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) ;  
         }  
         else  
         {  
             pDC->FillSolidRect(&lpDrawItemStruct->rcItem, GetSysColor(COLOR_WINDOW)) ;  
             pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;   
         }  
 //--------------- Full selection - highlight -----------------------  
         pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));  
         UINT        uFormat  = DT_LEFT ;  
         ::DrawText(lpDrawItemStruct->hDC, lpBuffer, strlen(lpBuffer),   
              &lpDrawItemStruct->rcItem, uFormat) ;  
         pDC->SelectStockObject(SYSTEM_FONT) ;  
 //Enable measureitem().  
         this->OnSetFont(NULL, NULL);  //配合MeasureItem()用的        
     }  
 }  

目前這個範例裡面還看不出是怎麼讓文字斷行的,但可確定的是,由於這個function會重新變更欄位的字體與背景顏色。因此當同時還有使用到OnNMCustomdrawLst()的話,OnNMCustomdrawLst()所繪製的顏色會被DrawItem()所覆蓋掉(因OnNMCustomdrawLst()比DrawItem()早執行),所以這邊要注意。
如有找到換行的方法,之後再補上。
PS.測試結果,DrawText似乎會在遇到newline時,就會把後面的文字自動輸出到下一行。

Problem:
1.在移動欄位title時,欄位內顯示之文字並不會像CListCtrl一樣,會加上"..."來代表有文字被遮蓋。
看來這邊是需要自行處理。(變更欄位大小時,畫面不會更新到其他地方)
2.上一次顯示文字之尾端總是會殘留在下一個欄位的開頭,這邊也需要另外再處理。
3.此範例所繪製的文字會貼齊於Cell的最左側邊界,會與CListCtrl顯示結果不同。

新找到的:Multi-line List Control
這篇提供的方法可以解決P.1、P.2、P3的問題。
差別在於,這篇提供的畫文字方法是CDC::DrawTextEx。這樣就可以讓CListCtrl自行去處理上述之問題,不然要手動處理的話,倒是挺麻煩的。如此一來,函式也變得比較乾淨了。

修改過後的函式如下:
 void CXListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)   
 {  
     LPDRAWITEMSTRUCT lpDrawHighLight = new DRAWITEMSTRUCT();  
     CString cstrSubitemText = "";  
     CRect rcSubItemRect;          
     CDC* pDC =     CDC::FromHandle(lpDrawItemStruct->hDC);        //不用釋放  
     LV_ITEM lvi;  
     rcSubItemRect.SetRectEmpty();  
     LV_COLUMN lvc, lvcprev ;  
     ::ZeroMemory(&lvc, sizeof(lvc));  
     ::ZeroMemory(&lvcprev, sizeof(lvcprev));  
     lvc.mask = LVCF_WIDTH | LVCF_FMT;  
     lvcprev.mask = LVCF_WIDTH | LVCF_FMT;  
     //lpDrawItemStruct->rcItem為目前所要畫出文字的row的邊界。  
     for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     {  
         // Get Previous Column Width in order to move the next display item  
         if ( nCol > 0 )   
         {              
             GetColumn(nCol-1, &lvcprev) ;  
             lpDrawItemStruct->rcItem.left += lvcprev.cx;  
             //lpDrawItemStruct->rcItem.right += lpDrawItemStruct->rcItem.left;            //會影響到最後一個SubItem的顯示長度。  
         }  
 //--------------- Full selection - highlight -----------------------  
         //Let Drawed highlight like the CListCtrl do it.  
         ::memcpy(lpDrawHighLight, lpDrawItemStruct, sizeof(DRAWITEMSTRUCT));  
         lpDrawHighLight->rcItem.left += this->GetStringWidth(" ");        //保留開頭的空白。讓行為同CListCtrl。  
         if ( lpDrawItemStruct->itemState & ODS_SELECTED )  
         {  
             pDC->FillSolidRect(&lpDrawHighLight->rcItem, GetSysColor(COLOR_HIGHLIGHT)) ;   
             pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT)) ;  
         }  
         else  
         {  
             pDC->FillSolidRect(&lpDrawHighLight->rcItem, GetSysColor(COLOR_WINDOW)) ;  
             pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT)) ;   
         }  
 //--------------- Full selection - highlight -----------------------  
 //-------------- Draw item -------------------------  
         pDC->SelectObject(GetStockObject(DEFAULT_GUI_FONT));  
         if ( !this->GetSubItemRect(lpDrawItemStruct->itemID, nCol, LVIR_BOUNDS, rcSubItemRect) ) {  
             continue;    };  
         //::DrawText(lpDrawItemStruct->hDC, lpDisplayBuf, nShowWordsLen, &lpDrawText->rcItem, uFormat) ;  
         rcSubItemRect.left += this->GetStringWidth(" ");  
         rcSubItemRect.right -= this->GetStringWidth(" ");  
         cstrSubitemText = this->GetItemText(lpDrawItemStruct->itemID, nCol);  
         pDC->DrawTextEx(cstrSubitemText, rcSubItemRect, (DT_LEFT|DT_NOPREFIX|DT_TOP|DT_WORD_ELLIPSIS), NULL);  
         pDC->SelectStockObject(SYSTEM_FONT) ;  
 //-------------- Draw item -------------------------  
 //Enable measureitem().  
         this->OnSetFont(NULL, NULL);          
     }    //End of for ( int nCol=0; GetColumn(nCol, &lvc); nCol++)  
     if ( lpDrawHighLight != NULL )    {  
         delete lpDrawHighLight;  
         lpDrawHighLight = NULL;  
     }  
 }  

[CListCtrl]改變行高

由於MFC裡的CListCtrl並無提供改變行高的函式,因此就需要透過改變繪圖方式,來達到改變行高的效果。

這邊找到的參考資料如下:
1.Report control - with category
2.Changing Row Height in an owner drawn Control
3.CListCtrl 行高问题最终解决方法

裡面提到的方式都是使用OnSetFont()以及MeasureItem()來搭配使用。

另一種就是直接在OnNMCustomdrawLst()裡面,進行文字繪製。
Expandable List Control to Accept Multilines

OnNMCustomdrawLst()使用方式可參考[CListCtrl]改變儲存格文字顏色

由於使用OnNMCustomdrawLst()的方式比較複雜,所以底下就針對DrawItem()以及MeasureItem()兩個函式來說明。

在.h的部份:(SetFont()的部分稍後說明)
 void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) ;  
 afx_msg LRESULT    OnSetFont(WPARAM wParam, LPARAM lParam);  
 afx_msg void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);  

在message map部分:(無效的部份稍後說明)
 BEGIN_MESSAGE_MAP(CXListCtrl, CListCtrl)  
 //Multi-line  
     ON_MESSAGE(WM_SETFONT, OnSetFont)    //NOTE:無效  
     ON_WM_MEASUREITEM_REFLECT()        //NOTE:無效  
     ON_WM_MEASUREITEM()                //NOTE:無效  
 END_MESSAGE_MAP()  

在.cpp裡面要加上下列4個函式:
1.OnMeasureItem()
 void CXListCtrl::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
   CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct);  
 }  

這邊為何要又呼叫一次CListCtrl::OnMeasureItem我就不曉得原因了,因上面參考連結是有這項。但程式卻都沒進入到此函式。所以不加應該也沒關係吧?!XD

2.MeasureItem()
 void CXListCtrl::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)   
 {  
     // Get the LOGFONT for the current font.  
     LOGFONT lf;  
     ::ZeroMemory(&lf, sizeof(lf));  
     CFont* pFont = GetFont();  
     ASSERT_VALID(pFont);  
     if (pFont)   
         VERIFY(pFont->GetLogFont(&lf));  
     int nAdj(2) ;        //Sample is 4  
     m_nLinesPerRow = max(m_nLinesPerRow, 1);  
     if (lf.lfHeight < 0)   
         lpMeasureItemStruct->itemHeight = ((-lf.lfHeight+nAdj) * (m_nLinesPerRow));  
     else   
         lpMeasureItemStruct->itemHeight = ((lf.lfHeight+nAdj) * (m_nLinesPerRow));  
 }  

這邊實際上用來變更高度的是lpMeasureItemStruct->itemHeight,但由於抓到的並不是完整的文字高度,單行沒問題,三行以上就出錯了。所以在範例的部份,有加上平移值。這邊測試結果,如果平移值與顯示行數差值大於等於2時,最後一行文字就會被蓋掉。所以這個值還是要做動態的會比較好。
如有需要做到每行高度不同的話,後面乘上的顯示行數就需要針對顯示文字的行是做動態處理。
目前還沒想到好作法,之後再回來補充。

3.OnSetFont()
 LRESULT CXListCtrl::OnSetFont(WPARAM wParam, LPARAM lParam)  
 {  
     CRect rc;  
     GetWindowRect(&rc);  
     WINDOWPOS wp;  
     wp.hwnd = this->m_hWnd;  
     wp.cx = rc.Width() ;  
     wp.cy = rc.Height() ;  
     wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;  
     LRESULT lrReturn(Default());  
     SendMessage(WM_WINDOWPOSCHANGED, 0, reinterpret_cast<LPARAM> (&wp));  
     return lrReturn;  
 }  

在範例裡,這個函式僅是用來觸發MeasureItem()更新動作的一個事件而已。觸發MeasureItem()的事件很獨特,就是讓畫面有所變動,然後系統就會送回重新繪製item的訊息,接下來就會進到MeasureItem()來重新繪製每個item的狀況。
此方法在範例中能成功,但我不管怎麼試,就是試不出來,也找不到原因。最後就在DrawItem()結束後,直接送出視窗訊息。

以上就是改變行高的作法

程序員筆記: 不使用temp變數交換兩個整數

程序員筆記: 不使用temp變數交換兩個整數: "在交換兩個整數時往往需要一個暫存變數,舉例如下。"

Build docker image from multiple build contexts

Build docker image from multiple build contexts ...