Tổng hợp file .txt từ nhiều Folders vào file Excel

Liên hệ QC

baquang1984

Thành viên tiêu biểu
Tham gia
3/6/10
Bài viết
429
Được thích
44
Nghề nghiệp
Kỹ sư Lâm nghiệp
Em chào thầy, cô và các anh chị trên diễn đàn GPE
Do công việc của em cần tổng hợp nhiều file .txt có cấu trúc giống nhau từ các thành viên gửi về mỗi thành viên là một Folder. Do vậy nhờ thầy, cô và anh chị trên diễn đàn viết giúp em chương trình VBA để tổng hợp các file .txt này từ các Folder vào file Excel ạ
Yêu cầu của chương trình là khi chọn vào Buttom TỔNG HỢP chương trình sẽ cho phép chọn nhiều Folder chứa các file .txt cần tổng hợp, khi chọn xong chương trình tổng hợp theo yêu cầu sau:
Ở cột A "Tên Folder" chương trình sẽ ghi lần lượt tên Folder chứa file cần tổng hợp vào cột này khi tổng hợp
Ở cột B "Tên File" chương trình sẽ ghi lần lượt tên File chữa dữ liệu cần tổng hợp vào cột này khi tổng hợp
Ở cột C "Số TT", Cột D "X", Cột E "Y" chương trình tổng hợp và ghi dữ liệu có trong các file vào
Như file mẫu em gửi kèm ạ
Em cảm ơn thầy, cô và các anh chị trên diễn đàn nhiều ạ
 

File đính kèm

  • Hoi_GPE.rar
    19 KB · Đọc: 34
Uhm, C++, dùng MFC. Có xem lại code này rồi, port qua VBA được nhưng cực lắm.
Delphi sau này chắc cũng có đó, bạn Mạnh search help và thư mục Source VCL thử.
 
Lần chỉnh sửa cuối:
Upvote 0
Port dài quá, ngán, nên thôi, hì hì. Thôi tui up source code C++/MFC của nó lên đây cho bà con nào không có account ở CodeProject down về ngâm cứu, rãnh thì port từ từ qua VBA.
Chứ tui thì giờ độ lười nó hơi cao, và thấy không cần thiết lắm ;)
Bác Mạnh, bác Tuân nghiên cú source này và extent TOpenDialog, TOpenFileDialog trong Delphi để select multi folders được nè.
Về hook = VB/VBA với GetOpenFileName thì có thể tham khảo thêm ở đây:
 

File đính kèm

  • SelectDialog_Src.zip
    2.9 KB · Đọc: 7
Lần chỉnh sửa cuối:
Upvote 0
Port dài quá, ngán, nên thôi, hì hì. Thôi tui up source code C++/MFC của nó lên đây cho bà con nào không có account ở CodeProject down về ngâm cứu, rãnh thì port từ từ qua VBA.
Chứ tui thì giờ độ lười nó hơi cao, và thấy không cần thiết lắm ;)
Bác Mạnh, bác Tuân nghiên cú source này và extent TOpenDialog, TOpenFileDialog trong Delphi để select multi folders được nè.
Về hook = VB/VBA với GetOpenFileName thì có thể tham khảo thêm ở đây:
Mới coi xong cảm giác như Chim sẻ nhảy vào vườn rậm ấy ===\.-0-0-0-
Mã:
BOOL CSelectDialog::OnFileNameOK()
{
    if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(GetParent()->m_hWnd))
    {
        CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
        if (pWnd == NULL)
            return FALSE;

        m_SelectedItemList.RemoveAll();            // emptying list
        
        CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));

        int nSelected = wndLst1->GetSelectedCount();
        if (!nSelected)        // nothing selected -- don't retrieve list
            return FALSE;
        CString strItemText, strDirectory = m_strCurrendDirectory;
        if (strDirectory.Right(1) != _T("\\"))
            strDirectory += _T("\\");

        CString fileslist = _T("");
        pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
            (LPARAM)fileslist.GetBuffer(MAX_PATH));
        fileslist.ReleaseBuffer();

        strItemText = strDirectory + fileslist;
        if(nSelected == 1 && fileslist != _T(""))
        {
            m_SelectedItemList.Add(strItemText);
            return CFileDialog::OnFileNameOK();
        }
    }
    ::MessageBeep( MB_ICONQUESTION );
    return 1; //don't let the dialog to close
};

void CSelectDialog::OnFolderChange()
{
    m_strCurrendDirectory = GetFolderPath();
    CFileDialog::OnFolderChange();
};

void CSelectDialog::OnInitDone()
{
    m_strCurrendDirectory = GetFolderPath();
    CWnd* pFD = GetParent();

    HideControl(edt1);
    HideControl(cmb1);
    HideControl(stc2);

    //HideControl(cmb13);
    //HideControl(stc3);

    CRect rectCancel; pFD->GetDlgItem(IDCANCEL)->GetWindowRect(&rectCancel);
    pFD->ScreenToClient(&rectCancel);

    CRect rectOK; pFD->GetDlgItem(IDOK)->GetWindowRect(&rectOK);
    pFD->ScreenToClient(&rectOK);
    pFD->GetDlgItem(IDOK)->SetWindowPos(0,rectCancel.left - rectOK.Width() - 5, rectCancel.top, 0,0, SWP_NOZORDER | SWP_NOSIZE);

    CRect rectList2; pFD->GetDlgItem(lst1)->GetWindowRect(&rectList2);
    pFD->ScreenToClient(&rectList2);
    pFD->GetDlgItem(lst1)->SetWindowPos(0,0,0,rectList2.Width(), abs(rectList2.top - (rectCancel.top - 5)), SWP_NOMOVE | SWP_NOZORDER);

    CRect rectStatic;pFD->GetDlgItem(stc3)->GetWindowRect(&rectStatic);
    pFD->ScreenToClient(&rectStatic);
    pFD->GetDlgItem(stc3)->SetWindowPos(0,rectCancel.left - 375,rectCancel.top + 5, rectStatic.Width(), rectStatic.Height(), SWP_NOZORDER);

    CRect rectEdit1;pFD->GetDlgItem(cmb13)->GetWindowRect(&rectEdit1);
    pFD->ScreenToClient(&rectEdit1);
    pFD->GetDlgItem(cmb13)->SetWindowPos(0,rectCancel.left - 320,rectCancel.top, rectEdit1.Width() - 15, rectEdit1.Height(), SWP_NOZORDER);

    SetControlText(stc3, _T("Item name:"));
    SetControlText(IDOK, _T("Select"));

    m_wndProc = (WNDPROC)::SetWindowLong(pFD->m_hWnd, GWL_WNDPROC, (long)WindowProcNew);
    pFD->CenterWindow();
};

LRESULT CALLBACK CSelectDialog::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message ==  WM_COMMAND)
    {
        if (HIWORD(wParam) == BN_CLICKED)
        {
            if (LOWORD(wParam) == IDOK)
            {
                if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(hwnd))
                {
                    m_SelectedItemList.RemoveAll();            // emptying list
                    CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
                    if (pWnd == NULL)
                        return FALSE;

                    CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));

                    int nSelected = wndLst1->GetSelectedCount();
                    if (!nSelected)        // nothing selected -- don't retrieve list
                        return FALSE;
                    CString strItemText, strDirectory = m_strCurrendDirectory;
                    if (strDirectory.Right(1) != _T("\\"))
                        strDirectory += _T("\\");

                    int nItem = wndLst1->GetNextItem(-1,LVNI_SELECTED);
                    CString fileslist = _T("");
                    pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
                        (LPARAM)fileslist.GetBuffer(MAX_PATH));
                    fileslist.ReleaseBuffer();
                    //////////////////   Add directory names to list
                    while((nSelected--) > 0)
                    {
                        strItemText = wndLst1->GetItemText(nItem,0);
                        strItemText = strDirectory + strItemText;
                        DWORD attr = GetFileAttributes(strItemText);
                        if((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY))
                            m_SelectedItemList.Add(strItemText);                           
                        nItem = wndLst1->GetNextItem(nItem, LVNI_SELECTED);
                    }
                    //////////////////   Add FILE names to list
                    strItemText = _T("");
                    nSelected = wndLst1->GetSelectedCount();
                    if(nSelected > m_SelectedItemList.GetCount())
                    {
                        int MoreThanOnFile = fileslist.Find(_T("\""));
                        if(MoreThanOnFile != -1)
                        {
                            for(int i=0; i<fileslist.GetLength(); i++)
                                if(fileslist[i] != '\"')
                                {
                                    strItemText.AppendFormat(_T("%c"),fileslist[i]);
                                    if(fileslist[i-1] == '\"' && fileslist[i] == ' ')
                                        strItemText.Delete(strItemText.GetLength()-1);
                                }
                                else if(!strItemText.IsEmpty())
                                {
                                    m_SelectedItemList.Add((strDirectory+strItemText));
                                    strItemText.Empty();
                                }
                        }
                        else
                            m_SelectedItemList.Add(strDirectory+fileslist);
                    }
                    pDlg->EndDialog(IDOK);
                    return NULL;
                } // if IDOK
            }
        } // if BN_CLICKED
    }// if WM_COMMAND
    return CallWindowProc(m_wndProc, hwnd, message, wParam, lParam);
 
Upvote 0
Mới coi xong cảm giác như Chim sẻ nhảy vào vườn rậm ấy ===\.-0-0-0-
Mã:
BOOL CSelectDialog::OnFileNameOK()
{
    if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(GetParent()->m_hWnd))
    {
        CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
        if (pWnd == NULL)
            return FALSE;

        m_SelectedItemList.RemoveAll();            // emptying list
       
        CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));

        int nSelected = wndLst1->GetSelectedCount();
        if (!nSelected)        // nothing selected -- don't retrieve list
            return FALSE;
        CString strItemText, strDirectory = m_strCurrendDirectory;
        if (strDirectory.Right(1) != _T("\\"))
            strDirectory += _T("\\");

        CString fileslist = _T("");
        pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
            (LPARAM)fileslist.GetBuffer(MAX_PATH));
        fileslist.ReleaseBuffer();

        strItemText = strDirectory + fileslist;
        if(nSelected == 1 && fileslist != _T(""))
        {
            m_SelectedItemList.Add(strItemText);
            return CFileDialog::OnFileNameOK();
        }
    }
    ::MessageBeep( MB_ICONQUESTION );
    return 1; //don't let the dialog to close
};

void CSelectDialog::OnFolderChange()
{
    m_strCurrendDirectory = GetFolderPath();
    CFileDialog::OnFolderChange();
};

void CSelectDialog::OnInitDone()
{
    m_strCurrendDirectory = GetFolderPath();
    CWnd* pFD = GetParent();

    HideControl(edt1);
    HideControl(cmb1);
    HideControl(stc2);

    //HideControl(cmb13);
    //HideControl(stc3);

    CRect rectCancel; pFD->GetDlgItem(IDCANCEL)->GetWindowRect(&rectCancel);
    pFD->ScreenToClient(&rectCancel);

    CRect rectOK; pFD->GetDlgItem(IDOK)->GetWindowRect(&rectOK);
    pFD->ScreenToClient(&rectOK);
    pFD->GetDlgItem(IDOK)->SetWindowPos(0,rectCancel.left - rectOK.Width() - 5, rectCancel.top, 0,0, SWP_NOZORDER | SWP_NOSIZE);

    CRect rectList2; pFD->GetDlgItem(lst1)->GetWindowRect(&rectList2);
    pFD->ScreenToClient(&rectList2);
    pFD->GetDlgItem(lst1)->SetWindowPos(0,0,0,rectList2.Width(), abs(rectList2.top - (rectCancel.top - 5)), SWP_NOMOVE | SWP_NOZORDER);

    CRect rectStatic;pFD->GetDlgItem(stc3)->GetWindowRect(&rectStatic);
    pFD->ScreenToClient(&rectStatic);
    pFD->GetDlgItem(stc3)->SetWindowPos(0,rectCancel.left - 375,rectCancel.top + 5, rectStatic.Width(), rectStatic.Height(), SWP_NOZORDER);

    CRect rectEdit1;pFD->GetDlgItem(cmb13)->GetWindowRect(&rectEdit1);
    pFD->ScreenToClient(&rectEdit1);
    pFD->GetDlgItem(cmb13)->SetWindowPos(0,rectCancel.left - 320,rectCancel.top, rectEdit1.Width() - 15, rectEdit1.Height(), SWP_NOZORDER);

    SetControlText(stc3, _T("Item name:"));
    SetControlText(IDOK, _T("Select"));

    m_wndProc = (WNDPROC)::SetWindowLong(pFD->m_hWnd, GWL_WNDPROC, (long)WindowProcNew);
    pFD->CenterWindow();
};

LRESULT CALLBACK CSelectDialog::WindowProcNew(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    if (message ==  WM_COMMAND)
    {
        if (HIWORD(wParam) == BN_CLICKED)
        {
            if (LOWORD(wParam) == IDOK)
            {
                if (CFileDialog* pDlg = (CFileDialog*)CWnd::FromHandle(hwnd))
                {
                    m_SelectedItemList.RemoveAll();            // emptying list
                    CWnd* pWnd = pDlg->GetDlgItem(lst2);    //getting list
                    if (pWnd == NULL)
                        return FALSE;

                    CListCtrl* wndLst1 = (CListCtrl*)(pWnd->GetDlgItem(1));

                    int nSelected = wndLst1->GetSelectedCount();
                    if (!nSelected)        // nothing selected -- don't retrieve list
                        return FALSE;
                    CString strItemText, strDirectory = m_strCurrendDirectory;
                    if (strDirectory.Right(1) != _T("\\"))
                        strDirectory += _T("\\");

                    int nItem = wndLst1->GetNextItem(-1,LVNI_SELECTED);
                    CString fileslist = _T("");
                    pDlg->SendMessage(CDM_GETSPEC, (WPARAM)MAX_PATH,
                        (LPARAM)fileslist.GetBuffer(MAX_PATH));
                    fileslist.ReleaseBuffer();
                    //////////////////   Add directory names to list
                    while((nSelected--) > 0)
                    {
                        strItemText = wndLst1->GetItemText(nItem,0);
                        strItemText = strDirectory + strItemText;
                        DWORD attr = GetFileAttributes(strItemText);
                        if((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY))
                            m_SelectedItemList.Add(strItemText);                          
                        nItem = wndLst1->GetNextItem(nItem, LVNI_SELECTED);
                    }
                    //////////////////   Add FILE names to list
                    strItemText = _T("");
                    nSelected = wndLst1->GetSelectedCount();
                    if(nSelected > m_SelectedItemList.GetCount())
                    {
                        int MoreThanOnFile = fileslist.Find(_T("\""));
                        if(MoreThanOnFile != -1)
                        {
                            for(int i=0; i<fileslist.GetLength(); i++)
                                if(fileslist[i] != '\"')
                                {
                                    strItemText.AppendFormat(_T("%c"),fileslist[i]);
                                    if(fileslist[i-1] == '\"' && fileslist[i] == ' ')
                                        strItemText.Delete(strItemText.GetLength()-1);
                                }
                                else if(!strItemText.IsEmpty())
                                {
                                    m_SelectedItemList.Add((strDirectory+strItemText));
                                    strItemText.Empty();
                                }
                        }
                        else
                            m_SelectedItemList.Add(strDirectory+fileslist);
                    }
                    pDlg->EndDialog(IDOK);
                    return NULL;
                } // if IDOK
            }
        } // if BN_CLICKED
    }// if WM_COMMAND
    return CallWindowProc(m_wndProc, hwnd, message, wParam, lParam);
cái này có phải VBA không ạ. hicccc em xem mà không hiểu gì cả ạ. Mong bác kieu manh giúp em với
Cảm ơn bác nhiều!
 
Upvote 0
OH VÃI THẾ TƯỞNG VBA .... HÓNG HỤT :p
MÀ C LẠI VIẾT *.DLL HẢ
Vấn đề ở chỗ có thể tìm ra 1 lệnh duy nhất trong VBA để duyệt tới và chọn nhiều thư mục hay không. Tất nhiên không có 1 lệnh như thế. Còn nếu tự viết code thì có gì khó đâu.

Không có việc gì khó. Chỉ sợ ................ đầu lười suy nghĩ.

Nếu lập trình Windows API thì có thể dùng vd. (chỉ là ý tưởng sơ qua thôi) interface IShellFolder + method EnumObjects + ... Nhưng nói cho cùng thì sao phải khổ thế? Sao phải đi con đường đầy chông gai? Vì thực ra ta chỉ cần lấy về tên các thư mục được chọn, tức các chuỗi. Tất nhiên user phải có khả năng di chuyển tới thư mục đích trên drive cụ thể để chọn các thư mục con trong thư mục đích.

Thuật toán là:
1. Đặt trên UserForm 1 ListView với View = lvWIcon, 1 ComboBox, Label với Caption = "<"

2. Trong UserForm_Initialize dùng FileSystemObject để lấy các drive vào combobox. và chọn mục đầu tiên.

3. Trong combobox_change thì đọc ra thư mục hiện hành trên drive được chọn và nhập vào biến toàn cục currFolder. Đồng thời gọi sub listFolder

4. Sub listFolder: Trước hết xóa hết các item của ListView. Tiếp theo dùng FileSystemObject để lấy danh sách các thư mục con của thư mục currFolder. Với mỗi thư mục con thì tạo item cho ListView với Caption = tên thư mục con.

5. Với DoubleClick của ListView: đọc ra item đang được chọn với tên của thư mục được chọn -> đổi currFolder thành đường dẫn tới thư mục đang được chọn -> gọi listFolder.

6. Label2_Click: từ currFolder xác định thư mục cha của thư mục currFolder. Nếu có cha thì đổi currFolder thành thư mục cha rồi gọi listFolder. Nếu không có cha vì currFolder là thư mục chính trên drive thì không làm gì.

Như vậy user chuyển drive bằng cách chọn trong ComboBox. Đúp chuột lên item của ListView để chuyển thư mục currFolder thành thư mục được click và hiện các thư mục con trong ListView. Click Label2 để chuyển tới thư mục cha của thư mục hiện hành. Nếu user nhấn OK thì 1 mảng với tên các thư mục được chọn sẽ được trả về. Trong ví dụ thì các tên sẽ được hiện bằng Debug.Print.

Lưu ý:
1. Nếu lập trình trong Delphi thì Delphi có control ListView. Nhưng cũng có thể dùng API để tự tạo ListView. Nói cho cùng thì Delphi cũng tạo ListView bằng API. Trong VBA cũng có thể tạo ListView bằng API.

Tóm lại thuật toán là thế. Còn implement trong Delphi, VB, VBA thì tùy. Cũng có thể không dùng ListView mà thêm các Label thay cho thêm các item vào ListView. Tất nhiên phải sắp xếp các Label theo hàng và cột. Và thay đúp chuột trên ListView bằng đúp chuột trên các Label.

Thuật toán chỉ là 1 nhưng các chi tiết implement thuật toán đó có thể tùy biến (ngôn ngữ lập trình, controls).

2. Hiện code hiện cả thùng rác và các thư mục "cấm" của system. Đây chỉ là ví dụ, chi tiết thì ai thích người ấy tự làm.

3. Code chưa xử lý nhiều trường hợp lỗi có thể sảy ra vì nó chỉ là ví dụ.

4. Có thể chọn icon cho các item của ListView để đẹp mắt. Tôi không làm vì đây chỉ là ví dụ.

5. Code được test trên Windows XP Home 32 bit + Excel 2010 32 bit, và Windows 10 64 bit + Excel 2007 32 bit.
 

File đính kèm

  • SelectFolders.xlsm
    30.5 KB · Đọc: 27
Upvote 0
Chi khổ vậy, dùng quách cách của bạn khongtu19bk không đơn giản hơn à ? Phát minh lại cái bánh xe làm gì với UserForm, vBA củ chuối.
Bài đã được tự động gộp:

Kg thì chỉ cần msoFolderPicker hay API SHBrowseForFolder cũng đủ rồi, shoe, chọn, ok, chán, thôi thì click Cancel, cũng ra multi select folder, làm Gui UserForm cùi bắp chi cho cực
 
Lần chỉnh sửa cuối:
Upvote 0
Về code dài ngắn, khổ hay không, chưa chắc cái nào hơn cái nào. Chắc chắn code của ta không phức tạp với những người biết VBA, chắc chắn không dài. Vậy ai khổ đây, hay đọc mà không hiểu nhỉ. Không đơn giản hơn. Đọc code thì thấy code của ta thì tất cả các dòng rất nhiều người có thể tự viết. Cái mấu chốt chỉ là ý tưởng.

Không hiểu ý thì nói cho hiểu nhé. Ta cố tình không dùng API vì API với nhiều người vẫn còn xa lạ. Không phải ta không biết SHBrowseForFolder nhưng đó là API rồi. Nói chung là không hiểu được ý của người ta thì nên im lặng.

1. Về code của khongtu19bk khi mở thì ví dụ ta có thư mục C:\. Ví dụ trong C:\ có thư mục Excel. Nếu ta muốn liệt kê các thư mục con của Ecel thì lại phải nhấn nút Open -> duyệt tới và chọn Excel. Trong code của tôi chỉ là đúp chuột trên Excel.

2. Trong code của khongtu19bk nếu muốn chọn vài thư mục con thì phải click từng thư mục. Trong code của tôi có thể click 1 thư mục -> giữ Shift và click thư mục khác. Cũng có thể click "điểm trống" ở phía trên bên trái 1 thư mục rồi giữ nhấn và kéo tới điểm khác. Toàn bộ các icon trong vùng hình chữ nhật sẽ được chọn. Tất nhiên có thể giữ Ctrl và click từng icon để chọn nhiều.

Có đúng như thao tác trong Excplorer không? Y hệt hoặc gần y hệt như trong Explorer. Với code của khongtu19bk thì không như thế.

3. Với code của tôi mà thêm icon thì nhìn như trong các thư mục trên đĩa không? Đâu có là danh sách các tên trong từng dòng?

Đọc code, nhìn biểu diễn mà không nhìn thấy sự khác nhay giữa 2 code, không hiểu gì thì quá yếu.

Nói chung giỏi gì thì chuyên về cái đó đi, những cái không hiểu thì ngồi im mà nghe người khác nói. Ta đã chỉ ra cái vụ unicode hồi nào với BOM và không BOM, cãi chầy cối rồi cuối cùng vẫn không biết mở tập tin sao cho đúng. Còn lý lẽ: thế ai đó không biết chọn encoding thì sao. Thì cho nghỉ việc thôi chứ sao nữa. Thế sếp giao cho việc mà cần mở CSV trong Excel mà lại không biết mở thì sao? Thì xin nghỉ việc chứ sao nữa. Lý lẽ là tôi có tập tin unicode nhưng tôi mở trong Word nhưng không biết chọn encoding sao cho đúng thì chỉ là lý sự cùn. Không biết mở thì học cách mở. Học mà vẫn không biết thì xin nghỉ việc. Thế thôi.

Dù sao đây chỉ là ví dụ khác với ví dụ của khongtu19bk. Còn hơn nhiều những người chỉ biết mỗi cách LOOP hoặc copy code của người khác từ trên mạng về và tìm cách dịch sang VBA. Con người ta ăn nhau ở cái ý tưởng, cách tư duy, chịu suy nghĩ. Còn trưng code của người khác để người ta nhìn vào thấy hoa mắt, dùng các từ shlwapi.dll, shell32.dll tới msi.dll cho dân đen nhìn thấy mà sợ thì chỉ là trò làm cho bạn gái lác mắt mà thôi. Ta không phải thuộc loại đó.

Dù sao ta cũng đưa ra 1 ý tưởng, và có code đàng hoàng. Còn hơn viết 1 loạt bài chỉ ở mức ăn tục nói phét, chưa đưa ra được 1 dòng code, thì đừng lên mặt dạy người khác nhé.
 
Upvote 0
Hì hì, bác này thù dai thù vặt ghê nhỉ. Nội cái vụ BOM mà nói tới nói lui hoài.
Cái tôi muốn select multi foler cuối cùng là cái này nè bác. Nhưng tôi tìm chưa ra, dù đã đào tùm lum các dll của Windows. Nó là undocument function API.
Ý tôi muốn là chỉ cần tìm, dùng được API này thì mọi chuyện sẽ đơn giản. Vì các giải pháp, code hiện tại của khongtu19bk, của bác, hay cách hook GetOpenFileName tôi đưa ra đều không chọn được multi folder cùng lúc trong nhiều thư mục khác nhau, ổ đĩa khác nhau.
Nên tôi nói đơn giản nhất là loop, chọn từng thư mục bất kỳ, không chọn nữa thì Cancel. Chả cần form fiec, code kiết gì cả. Đơn giản nhất.
Và nói luôn là file của bác tôi chả cần download mà xem, vì biết cũng chỉ nhiêu đó, không có cái gì hay ho hay mới mẽ cả. Ba cái userform với VBA này thì bác chỉ khè được các anh chị dân tin học VP, làm VP ở đây thôi, dân newbie, amatuer VBA, chứ với dân coder chuyên nghiệp, nó là trò con nít.
Tôi nói không cần thiết vì mục đích của chủ thớt ban đầu là xử lý txt file, chọn multi folder chỉ là phụ. Có cũng được không có cũng chả sao.
Chả cần phải làm cái form, mang 1 đống code vào để chỉ làm mục đích chọn multi folder. Cái chính chủ thớt muốn là xử lý file txt thôi. Hết. Cái này bạn khongtubk19 đã làm rồi.
 

File đính kèm

  • 1.png
    1.png
    19.1 KB · Đọc: 26
Upvote 0
úi ra xem cái hình có check check thế kia là mê tê cứng ròi ... có code VBA úp cho mạnh học với thì tuyệt vời ông mặt trời Or Delphi thì cũng mầm tạm chút ... còn code C thì chỉ dòm xong đoán mò được vài từ hay vài dòng thui ( Nói chung là tịt )
 
Upvote 0
Mới coi xong cảm giác như Chim sẻ nhảy vào vườn rậm ấy ===\.-0-0-0-
...
cái này có phải VBA không ạ. hicccc em xem mà không hiểu gì cả ạ. Mong bác kieu manh giúp em với
Cảm ơn bác nhiều!
Hai bạn tìm cái anh chàng chiên diên Xê Cọng Cọng đề nghị dạy 200 đô la mẽo một tiết ấy.
Mượn anh ta giải thích giùm cho. Có lẽ anh ta cũng không từ chối chút tiền lẻ vô nhớt xe mát da.

(tiếc quá, không ai viết code COBOL cho mình có dịp phét)
 
Upvote 0
Trên Delphi, C++, .NET thì thư viện không có sẳn control nào như thế, nhưng ngoài thị trường thì hằng hà sa số các cty, cá nhân viết bán hoặc free các custom control, class dạng này. Nhiều không đếm xuể...
Trên Delphi, bạn Mạnh thử TFileOpenDialog với options fdoPickFolders Or fdoAllowMultiSelect thử xem sao. Do máy cùi bắp vp của tui không có cài RAD Studio nên không thử được.
Còn custom component làm sẵn thì bạn Mạnh tham khảo vài cái ở đây thử:
1. http://www.gtro.com/delphi/gtrocheckshelltreeview_e.php
2. https://www.ssware.com/articles/shb...bout-the-windows-folder-browser-component.htm
3. https://www.jam-software.com/shellbrowser_delphi/
....
Nếu muốn dùng cho VBA thì phải build DLL cho VBA gọi thôi, không còn cách nào khác, hay viết OCX.
 
Upvote 0
Trên Delphi, C++, .NET thì thư viện không có sẳn control nào như thế, nhưng ngoài thị trường thì hằng hà sa số các cty, cá nhân viết bán hoặc free các custom control, class dạng này. Nhiều không đếm xuể...
Trên Delphi, bạn Mạnh thử TFileOpenDialog với options fdoPickFolders Or fdoAllowMultiSelect thử xem sao. Do máy cùi bắp vp của tui không có cài RAD Studio nên không thử được.
Còn custom component làm sẵn thì bạn Mạnh tham khảo vài cái ở đây thử:
1. http://www.gtro.com/delphi/gtrocheckshelltreeview_e.php
2. https://www.ssware.com/articles/shb...bout-the-windows-folder-browser-component.htm
3. https://www.jam-software.com/shellbrowser_delphi/
....
Nếu muốn dùng cho VBA thì phải build DLL cho VBA gọi thôi, không còn cách nào khác, hay viết OCX.
1/ Thử build DLL úp lên cho Mạnh thử quậy chút xem sao .... nếu tốt Mạnh xài ké nhét vào cái DLL vb6 của Mạnh xài khi cần thiết ( Add Resoure VB6 )

2/ Nếu nó là DLL API thì thử trên VBA xem sao ?!

3/ Cũng đang tính khi nào rãnh Úp bài hỏi cách Add Resource trên Delphi cách nó làm như thế nào và lấy ra như thế nào ??? VB6 thì mạnh biết .... còn Delphi thì tịt .... có link nào hay code gì chỉ dùm !?

Cảm ơn
 
Upvote 0
Hì hì, bác này thù dai thù vặt ghê nhỉ. Nội cái vụ BOM mà nói tới nói lui hoài.
Không phải thù dai. Tranh luận đúng sai là chuyện thường, nhưng tôi không thích kiểu tranh luận cù nhầy.
Cái tôi muốn select multi foler cuối cùng là cái này nè bác. Nhưng tôi tìm chưa ra, dù đã đào tùm lum các dll của Windows. Nó là undocument function API.
Ý tôi muốn là chỉ cần tìm, dùng được API này thì mọi chuyện sẽ đơn giản. Vì các giải pháp, code hiện tại của khongtu19bk, của bác, hay cách hook GetOpenFileName tôi đưa ra đều không chọn được multi folder cùng lúc trong nhiều thư mục khác nhau, ổ đĩa khác nhau.
Nên tôi nói đơn giản nhất là loop, chọn từng thư mục bất kỳ, không chọn nữa thì Cancel. Chả cần form fiec, code kiết gì cả. Đơn giản nhất.
Và nói luôn là file của bác tôi chả cần download mà xem, vì biết cũng chỉ nhiêu đó, không có cái gì hay ho hay mới mẽ cả. Ba cái userform với VBA này thì bác chỉ khè được các anh chị dân tin học VP, làm VP ở đây thôi, dân newbie, amatuer VBA, chứ với dân coder chuyên nghiệp, nó là trò con nít.
Tôi nói không cần thiết vì mục đích của chủ thớt ban đầu là xử lý txt file, chọn multi folder chỉ là phụ. Có cũng được không có cũng chả sao.
Chả cần phải làm cái form, mang 1 đống code vào để chỉ làm mục đích chọn multi folder. Cái chính chủ thớt muốn là xử lý file txt thôi. Hết. Cái này bạn khongtubk19 đã làm rồi.
Nếu ở bài #72 bạn viết thế này thì tôi sẽ chẳng trả lời bạn gì cả. Vì thực chất tôi không trả lời cho chủ chủ đề, cho bạn hay bất cứ ai khác ngoài kieu manh. Và tôi cho là hiểu ý kieu manh như thế. Chỉ có kieu manh mới có quyền giải thích cụ thể hơn cho tôi về yêu cầu của mình. Viết bài trong một chủ đề nào đó không có nghĩa là trả lời cho vấn đề của chủ chủ đề. Đôi khi là sự trao đổi với người khác trong số những người đọc chủ đề. Tôi không quan tâm bạn muốn gì nên bạn không cần phải giải thích cho tôi.

Trong bài #72 bạn có thể thông báo các mong đợi của mình cho mọi người. Nhưng bạn chọn cách chê bai, nói khóe bài của tôi. Ai là người thù dai đây bạn. Bạn không cần trả lời vì đây là câu hỏi tu từ. Và tôi cũng không cần câu trả lời. Khi viết trả lời cho kieu manh thậm chí tôi không đọc tất cả các bài, không biết tới sự tồn tại của ý tưởng của khongtu19bk. Bài của tôi không có ý là nên dùng thay cho bất cứ cái gì. Nó chỉ nhằm mục đích chỉ ra là: có thể tự viết code để lấy về nhiều thư mục, và có đặc điểm giống như ta thao tác chọn nhiều thư mục con trong Explorer, và code đó hoàn toàn có thể ngắn gọn và dễ hiểu. Chỉ ra khả năng, và sự đơn giản của nó. Thế thôi. Tôi không nói là dùng nó để thay thế cái gì.

Tôi nhắc lại là tôi đã không quan tâm bạn muốn gì. Tôi trả lời cho mỗi kieu manh thôi. Những thằng chả đưa ra một code cụ thể nào mà chỉ ngồi nói phét thì tôi khinhh. Giỏi thì đưa ra code của mình cho mọi người học tập. Cho mọi người thấy cái thiên tài của mình. Cho mọi người ngưỡng mộ. Còn nếu không đưa ra được code thì ngồi im nghe người khác nói. Nếu thay vì code chỉ phun ra những từ "kêu to" thì quá tầm thường. Chỉ hù họa được bọn không biết gì, các bé mới lớn mà thôi. Quá tầm thường.

Nhắc lại: Nếu giỏi thì tung code ra cho mọi người ngưỡng mộ. Còn không thì đừng chê bai, nói khóe. Ghét nhất những bọn ăn tục nói phét, cù nhầy, lý sự cùn.
 
Upvote 0
Tui đã nói là code C++/MFC tui đã có từ lâu lắc rồi mà không tin. Chả ai rảnh đâu mà nói xạo.
Vấn đề là tui thấy không cần thiết phải 1 viết thêm 1 cái DLL wrap cái code này lại, để export 1 hàm ra cho chọn multi folder.
Cái tôi muốn là tìm ra API có sẵn trong đống DLL của Windows mà MS coder đã viết để dùng cho khỏe. Làm được như cái hình tui post ở trên. Thế thôi.
File đính kèm là EXE tui đã build release mode, code = Visual C++, dùng MFC. Bà con có thể test thử.
List các files, folder mà bà con đã chọn lưu trong HKEY_CURRENT_USER\Software\ThangCuAnh, bà con có thể test xong thì vào đó xóa cho sạch máy.
Code C++/MFC tui không đính kèm vì post lên bà con cũng không hiểu, như Kieumanh nói như "Chim sẻ nhảy vào vườn rậm" ấy, và nó dù code của tui, nhưng sở hữu của cty tôi đang làm, dùng trong nhiều sản phẩm, không open source được.
File Exe bảo đảm sạch, bà con an tâm
 

File đính kèm

  • TestSHBrowseForFolderHook.zip
    17 KB · Đọc: 9
Upvote 0
Sao không thấy có Check box chọn nhiều Folder nhỉ
Capture.JPG
 
Upvote 0
Code này chỉ test thôi bạn, không có phần modify style của TreeView của SHBrowseForFolder để bật tính năng checkbox.
Bấm cái mũi tên -> để add thư mục cần chọn vào 1 list
 
Upvote 0
Sao không thấy có Check box chọn nhiều Folder nhỉ
Tôi hiểu cái nỗi khổ của bạn.

Nếu mắt không nhìn thấy, mũi không ngửi thấy thì lòng thanh thản. Còn nếu người ta chỉ nhử nhử cái đùi gà trước mặt nhưng không cho, trong tầm tay mà không với tới được, thì ................ không có cái khổ nào như cái khổ này. :D

Bạn đã nói là chỉ cần chút gợi ý ABC thôi để bạn từ đó phát triển lên. Vậy tôi cho bạn ABC. Trước hết hãy chạy EXE xem đúng ý chưa. Tất nhiên chỉ ABC còn tôi không còn hứng phát triển lên. Vd. viết phục vụ Unicode. Tôi chỉ dùng Delphi 5 thôi. Tất nhiên có những bộ controls unicode cho Delphi 5 nhưng hồi xưa tôi cài để vọc chứ bây giờ không dùng. Nói chung mấy trò API này khoảng hơn 20 năm trước tôi chơi hàng ngày. Bây giờ già rồi không chơi nữa. Vì chơi về system, API thì chơi hết rồi.

Chú ý:
- muốn chọn thư mục nào thì click vào nó. Muốn bỏ chọn do chọn nhầm thì click lần nữa vào nó. Nhưng không click ngay được sau khi chọn nhầm để bỏ chọn. Phải click thư mục khác mà mình muốn chọn rồi sau đó click thư mục chọn nhầm. CheckBox sẽ được đánh dấu nếu thư mục được chọn.
- chỉ click tên thư mục chứ không click checkbox. Code tự đánh dấu checkbox. Mà thậm chí click checkbox thì kết quả sẽ sai do code tự đánh dấu.
- khi nhấn OK mà có các thư mục được chọn thì chúng sẽ được nạp vào Memo.
- chương trình không phục vụ Unicode vì tôi viết trong Delphi 5.
- đã chạy thử trên XP Home + Excel 2010 32 bit, và Windows 10 64 bit + Excel 2007 32 bit.

Nếu vừa ý thì tôi sẽ gửi cho code viết trong Delphi 5.
 

File đính kèm

  • Project1.rar
    132.7 KB · Đọc: 13
Upvote 0
Tôi hiểu cái nỗi khổ của bạn.

Nếu mắt không nhìn thấy, mũi không ngửi thấy thì lòng thanh thản. Còn nếu người ta chỉ nhử nhử cái đùi gà trước mặt nhưng không cho, trong tầm tay mà không với tới được, thì ................ không có cái khổ nào như cái khổ này. :D

Bạn đã nói là chỉ cần chút gợi ý ABC thôi để bạn từ đó phát triển lên. Vậy tôi cho bạn ABC. Trước hết hãy chạy EXE xem đúng ý chưa. Tất nhiên chỉ ABC còn tôi không còn hứng phát triển lên. Vd. viết phục vụ Unicode. Tôi chỉ dùng Delphi 5 thôi. Tất nhiên có những bộ controls unicode cho Delphi 5 nhưng hồi xưa tôi cài để vọc chứ bây giờ không dùng. Nói chung mấy trò API này khoảng hơn 20 năm trước tôi chơi hàng ngày. Bây giờ già rồi không chơi nữa. Vì chơi về system, API thì chơi hết rồi.

Chú ý:
- muốn chọn thư mục nào thì click vào nó. Muốn bỏ chọn do chọn nhầm thì click lần nữa vào nó. Nhưng không click ngay được sau khi chọn nhầm để bỏ chọn. Phải click thư mục khác mà mình muốn chọn rồi sau đó click thư mục chọn nhầm. CheckBox sẽ được đánh dấu nếu thư mục được chọn.
- chỉ click tên thư mục chứ không click checkbox. Code tự đánh dấu checkbox. Mà thậm chí click checkbox thì kết quả sẽ sai do code tự đánh dấu.
- khi nhấn OK mà có các thư mục được chọn thì chúng sẽ được nạp vào Memo.
- chương trình không phục vụ Unicode vì tôi viết trong Delphi 5.
- đã chạy thử trên XP Home + Excel 2010 32 bit, và Windows 10 64 bit + Excel 2007 32 bit.

Nếu vừa ý thì tôi sẽ gửi cho code viết trong Delphi 5.
Cảm ơn Anh ... đó mới là tuyệt vời Ông Mặt trời ... Anh cho em xin code nghiên cứu
Nếu được Anh viết dùm Em code .... Em cho Cái Form vào DLL Dephi xong em gọi hàm thì quá tuyệt !
Em chạy Trên Office 2016x32 và Windows10x64
Máy Em cài Delphi 10.2.3
221756
 
Upvote 0
Cảm ơn Anh ... đó mới là tuyệt vời Ông Mặt trời ... Anh cho em xin code nghiên cứu
Nếu được Anh viết dùm Em code .... Em cho Cái Form vào DLL Dephi xong em gọi hàm thì quá tuyệt !
Em chạy Trên Office 2016x32 và Windows10x64
Máy Em cài Delphi 10.2.3
Thôi thôi. Bạn muốn ABC để nghiên cứu nên tôi bỏ công ra cho ABC. Bạn tự làm tiếp thôi.

Tất cả các hàm API mà tôi dùng thì bạn cũng từng đọc, từng dùng rồi. Chả có hàm nào lạ với bạn cả. Còn 2 macro TreeView_*** (Nếu thích bạn có thể thay bằng SendMessage - hãy đọc help trong Delphi để biết) cũng có luôn trong Delphi 5, và như vậy chắc cũng có trong Delphi mới hơn. Chả có hàm nào bạn chưa dùng cả. Mấu chốt chỉ là ý tưởng mà thôi. Code cũng ngắn cũn cỡn nên chắc là không làm bạn mệt.
Bài đã được tự động gộp:

À trong code chỉ có 1 chỗ duy nhất là
Mã:
if A and B > 0 then
Tôi nghĩ là nên thay bằng
Mã:
if A and B = B then
 

File đính kèm

  • test.rar
    6 KB · Đọc: 7
Lần chỉnh sửa cuối:
Upvote 0
Thôi thôi. Bạn muốn ABC để nghiên cứu nên tôi bỏ công ra cho ABC. Bạn tự làm tiếp thôi.

Tất cả các hàm API mà tôi dùng thì bạn cũng từng đọc, từng dùng rồi. Chả có hàm nào lạ với bạn cả. Còn 2 macro TreeView_*** (Nếu thích bạn có thể thay bằng SendMessage - hãy đọc help trong Delphi để biết) cũng có luôn trong Delphi 5, và như vậy chắc cũng có trong Delphi mới hơn. Chả có hàm nào bạn chưa dùng cả. Mấu chốt chỉ là ý tưởng mà thôi. Code cũng ngắn cũn cỡn nên chắc là không làm bạn mệt.
Bài đã được tự động gộp:

À trong code chỉ có 1 chỗ duy nhất là
Mã:
if A and B > 0 then
Tôi nghĩ là nên thay bằng
Mã:
if A and B = B then
Em mới thử code xong BrowseFolder rất đẹp và tiện ích ... nếu Anh điều chỉnh lại code cho nó khi chọn vào Checkbox hay folder thì nó hiểu như nhau nữa thì hoàn hảo
Em mở trên Delphi 10.2.3 mà code ko báo lỗi ( code đó anh viết trên Delphi 5 )

Hai hàm đó Em bổ sung vào thư viện Hàm API của em thật tuyệt

sao em tìm ko thấy dòng code sau ? hay anh mới viết thêm
Mã:
if A and B > 0 then
Capture.JPG
 
Lần chỉnh sửa cuối:
Upvote 0
Web KT
Back
Top Bottom