Thêm 1 dạng PicForm
Tôi thấy lúc trước trên diển đàn có tác giả làm PicForm dựa vào Comment… Và đây lại là dạng khác của PicForm, mời các bạn tham khảo.
Khi xưa ta bé ta ngu…
Ngày trước download file này ở các trang nước ngoài về, chỉ đơn giản thấy hay thì đưa lên… giờ xem lại code thấy.. buồn cười (code dài dòng, lúc chạy thì cà giật) ===> đâu cứ code nước ngoài viết là hay
He… he…
Sửa lại đây
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim mySel As Range
On Error Resume Next
If Not Intersect(Range("KeyCells"), Target) Is Nothing Then
Set mySel = Selection
ActiveSheet.Shapes(mySel.Address & "Final").Delete
ActiveSheet.Shapes(mySel.Value).Copy
With mySel
.Offset(0, 2).PasteSpecial
Selection.Name = .Address & "Final"
Selection.Left = .Offset(0, 2).Left: Selection.Top = .Offset(0, 2).Top
Selection.Width = .Offset(0, 2).Width: Selection.Height = .Offset(0, 2).Height
End With
End If
mySel.Select
End Sub
File này dùng 3 hình mẫu có sẳn trong sheet, các bạn có thể cải tiến, thậm chí không cần mấy hình mẩu này tôi nghĩ cũng ko có vấn đề (nếu trong máy tính của ta đã có sẳn)
(Record quá trình Insert hình rồi chỉnh lại code).
Lại tiếp tục cải tiến:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim PicRng As Range, Pos As String
Application.ScreenUpdating = False
On Error Resume Next
If Not Intersect(, Target) Is Nothing Then
Set PicRng = Range("G1").CurrentRegion '<— Dat ten cho vung tra cuu hinh
Pos = WorksheetFunction.VLookup(Target, PicRng, 2, 0) '<— Xac dinh vi trí chua file hinh tren PC
ActiveSheet.Shapes(Target.Address).Delete '<— Xoa hinh da dat ten truoc do
With ActiveSheet.Pictures.Insert(Pos) '<— Chen hinh moi
.Name = Target.Address '<— Dat ten cho hinh moi chính là dia chi cell
.Left = Target(1, 0).Left: .Top = Target(1, 0).Top '<— Dinh vi cho hinh
.Width = Target(1, 0).Width: .Height = Target(1, 0).Height '<— Dinh chieu rong, cao cho hinh
End With
End If
Application.ScreenUpdating = True
End Sub
Bỏ luôn mấy hình mẩu (lấy hình dựa vào đường dẩn)
Các bạn có thể dựa vào file này để làm PicForm (khá đơn giãn)
ANH TUẤN
www.giaiphapexcel.com/diendan/threads/th%C3%AAm-1-d%E1%BA%A1ng-picform.3721/#post536728
Ứng dụng AI và Chat GPT trong Quản trị nhân sự
Học xong khóa này, học viên có thể: Hiểu đúng bản chất AI, các nhóm AI phổ biến và cách AI “hoạt động” ở...
Xem khóa học
Bạn cho toàn bộ code này vào sheet nhé:
Khi bạn thêm bất cứ hình nào vào bảng tính thì validation cũng cập nhật
(Vùng chọn Validation là B5:B10)
Rê chuột vào để phóng to thì khó. Ta có thể thay bằng: Click chuột vào ảnh để phóng to <— Cái này quá dễ, record macro quá trình thay đổi size hình để có code
Chính xác là thế! Nếu không, chẳng lẽ có 2 code sự kiện Change trong cùng 1 sheet sao? Nó báo lỗi liền
Rê chuột đến hay di chuyển chuột đến thì cũng như nhau thôi. Tóm lại: Picture không có sự kiện này
Ta chỉ có thể điều khiển hình phóng to, thu nhỏ khi ta dùng chuột CLICK VÀO HÌNH thôi
Hyperlink ảnh tự động nghĩa là sao?
Hyperlink theo tôi hiểu nghĩa là CLICK VÀO NÓ SẼ DI CHUYỂN ĐẾN NƠI KHÁC (đến bảng tính khác, đến file khác hoặc 1 trang web)
Vậy nên bạn nói Hyperlink ảnh tự động tôi cũng chẳng hiểu công việc ấy là gì nữa
Hay bạn muốn rằng: Khi chọn Validation thì ảnh tự động insert mà không cần phải insert trước đó? Nếu là vậy thì đây là bài toán khác hoàn toàn. Đã có trên GPE rồi đấy thôi:
https://www.giaiphapexcel.com/forum/showthread.php?51408-Ch%C3%A8n-h%C3%ACnh-v%C3%A0o-cell-b%E1%BA%B1ng-h%C3%A0m-t%E1%BB%B1-t%E1%BA%A1o
Yêu cầu của bạn nếu làm thật kỹ cũng không phải dễ dàng gì
Bạn xem file đính kèm và test thử nha
(code quá trời luôn!)
Quên dặn bạn:
– Đừng bấm Alt + F8, chọn Sub để chạy gì cả
– Code được thiết kế tự động hóa hoàn toàn: Click chuột vào hình sẽ phóng to, click lần nữa sẽ thu nhỏ. Hoặc ta click chuột ra khỏi hình (chọn 1 cell nào đó) thì hình cũng sẽ được reset
– Khi chon Validation, nếu đường dẫn tại cell F1 không chưa hình nào (tức file không tồn tại) thì lập tức cửa sổ chọn Folder sẽ hiện ra cho bạn chọn lại thư mục chứa hình
– Bạn cũng có thể chủ động bấm vào nút Select Folder để chọn đường dẫn
vân vân… Từ từ khám khá nha. Code tren vẫn chưa được hay đâu (tại viết hơi vội)
Ngoài ra: Tôi dùng Excel 2010 nên không chắc trên Excel 2003 sẽ chạy thế nào
Tức là bạn muốn khi bấm nút Select Folder thì ảnh chèn luôn?
Vậy sửa SelectFolder thành:
Đồng thời thêm 1 Sub nữa:
Không phải là tôi cố tình viết cho Excel 2010 mà là vì tôi không có bản Office 2003 để test nên không biết được lỗi phát sinh từ đâu
Nếu bạn dùng Excel 2003, để tìm lỗi, hãy bỏ mấy dòng On Error Resume Next rồi test xem khi lỗi xuất hiện nó đánh dấu vàng tại vị trí nào. Từ đó ta mới đoán bệnh được
***
Cám ơn thày ! Nó báo lỗi tại dòng màu xanh đậm trên ạ !
Lỗi này chỉ có thể có khi: Bạn chạy trực tiếp sub trên bằng cách Alt + F8 để chọn Sub thay vì click vào hình
Còn lại, Application.Caller chẳng liên quan gì đến version của office cả (Excel 2003 cũng dùng được)
Bạn có để ý thấy trong file của bạn tuy nhìn thấy 5 hình nhưng thực chất là 10 hình không?
Tức là: 5 hình nằm dưới 5 hình
Kiểm tra lại xem
(như vậy làm sao mà code chạy được: Vì 2 hình trùng tên)
Excel 2003 và 2007 sẽ khó phát hiện vụ này
Excel 2010 chỉ cần Alt + F10 sẽ thấy liền
————
Mà cũng không hiểu tại sao lại có cái vụ trùng hình vầy nữa? Code ở trên người ta đã tính cả rồi: Chèn hình mới là lập tức xóa hình cũ trước đó. Vậy mà cũng có vụ trùng, chẳng biết ở đâu ra nữa
Muốn gỡ xuống cái file thì bạn bấm sửa, Đổi sang khung lớn, chọn Tải file từ máy, tại đây bạn thấy cái file của bạn rồi bấm Remove thôi!
==========================
Cái file của bạn đã được chỉnh sửa, giờ bạn tự check lại xem còn lỗi không, giờ làm biếng test quá!
Tại Sub InsertPic, bạn thay câu lệnh này:
Thành câu lệnh này thử xem sao!
Nhưng quan trọng là Excel 2003 nó chịu với Shapes mà nó không chịu với Pictures mới đau!
Em kiểm tra kỹ rồi, ai không tin thì cứ thử thôi. Excel 2007 trở về sau mới sử dụng được với nó!
Và để chắc chắn nhất, cứ hỏi bạn Ngoai Thanh về vấn đề này mà sau khi em đã sửa code là biết liền!
VÔ LÝ!
Thế chẳng lẽ Excel 2003 ta không Insert được Picture?
Vậy thì dòng code ActiveSheet.Pictures.Insert(FileName) chẳng đã dùng từ đởi office nào rồi sao?
Đó không phải là Picture và Pictures object thì gọi là gì?
Gì mà ngại chứ bạn!
Luôn luôn giúp đở và chia sẻ kiến thức với mọi người trong khả năng có thể <— Đó là tiêu chí của tôi
Để mai tìm máy tính khác test thử xem (trên Excel 2003)
Mình đành.. bó tay rồi
Tìm khắp cty cũng chẳng có máy nào còn xài Office 2003. Lượm được 1 bộ Potable Office 2003, mừng quá test 1 phát thì… ôi thôi, nó chẳng hổ trợ VBA
Thời buổi này còn xài Office 2003 rõ khổ (vì sẽ nhận được ít sự trợ giúp)
Xài cái gì là tùy theo sở thích và quan điểm của cá nhân hoặc tổ chức
Có điều các bạn cũng thấy trên mạng giờ người ta xài đến Office 2013 (thậm chí là 64bit). Mình còn "lẹt đẹt" tận đâu thì… có trục trặc gì tự mò vậy
Nếu là một đối tác nước ngoài gửi cho file XLSX, XLSM, thậm chí là có code VBA bên trong thì chắc họ (hoặc sếp của họ) đã không nói vậy rồi.
Lúc đó họ (hoặc sếp họ) phải làm sao nhỉ? Suy nghĩ xem!
Tính mình rất hiếu kỳ. Mỗi khi gặp 1 vấn đề hơi "lạ lạ" là phải nhất định tìm hiểu tận gốc mới thôi
Trường hợp của bạn mình suy nghĩ mãi cũng không thấy có vấn đề gì. Ngoại trừ dòng lệnh LockAspectRatio = msoFalse không dùng được trên Excel 2003 thì các code còn lại là hoàn toàn tương thích
Tuy nhiên, để chắc ăn thì phải test trực tiếp… Cũng đã cố tìm máy nào đó có Office 2003 mà đành.. bó bột thôi
Ẹc… Ẹc… Tóm lại là: thua
(Để vài bữa hỏi thử xem ai có bộ Potable Office có hổ trợ VBA sẽ tính tiếp)
Chen ngang tí.
Trước hết góp ý về code trong bài #35 và #43
Code trên không chuẩn. Ta xét vd. trong Folder có 2 ảnh. Khi thực hiện (A) cho ảnh đầu tiên thì Target = Nothing. Hậu quả là mọi dòng lệnh trong InsertPic đều sai. Do ta dùng "On Error Resume Next" để che "mụn nhọt" nên không thấy sai. Nhưng kết quả là ảnh 1 không được nhập vào đâu cả. Ảnh 2 sẽ được nhập vào A5.
Tóm lại nếu trong folder có 1 ảnh thì không có ảnh nào được load. Nếu có n ảnh thì chỉ có (n – 1) ảnh được load. Để khắc phục thì đổi thành
Theo lôgic thì click lần đầu tiên vào ảnh thì ảnh phải phóng to vì ảnh hiện thời đang nhỏ. Nhưng với code hiện thời thì phải click lần thứ 2 thì ảnh mới to. Tức với mỗi ảnh ta tốn 1 click vô ích. Để khắc phục thì đổi code trong ShpResize
thành
—————
Vấn đề Pictures trên 2003 thì tôi không rõ vì có 2003 đâu để mà test. Nhưng nói cho cùng thì bạn muốn làm được việc chứ đâu phải lấy vợ mà bắt buộc phải "hoặc "em này" hoặc sẽ không em nào cả"?
Tóm lại, bạn không thấy là "cô" WorkSheet.Shapes.AddPicture vừa nết na, chăm làm, duyên dáng mà lại … ăn ít à?
Chổ này thì đúng. Em sơ sót
Nhưng chổ này
Thì em nghĩ là sai! Lúc đầu AlternativeText chưa có gì, mà bMark = (Len(.AlternativeText) > 0) nên bMark sẽ =FALSE
Vậy nên xét điều kiện khi bMark=FALSE mới phóng to ảnh là chính xác rồi còn gì
Nếu sửa như anh thì click vào chẳng có chuyện gì xãy ra cả
Toàn bộ code của em viết là thế này:
Có khi anh đang nói đến code nào đó đã bị "độ" lại cũng không chừng
TÁC GIÁ CODE LÀ EM đấy anh à!
Dù là bài 35 hay 36 hay số mấy thì code đó cũng là của em
—————
Anh xem kỹ lại đi: Cả code ở bài 35 và 43 đều không có cái vụ .AlternativeText = "tên ảnh" đâu
Tất cả 2 code trong 2 bài ấy đều đặt điều kiện vầy: bMark = (Len(.AlternativeText) > 0)
Code bài 35:
Code bài 43:
Còn chuyện có tên ảnh trong AlternativeText thì đó cũng là sơ suất của người ta, chẳng ảnh hưởng gì đến code cả. Dù lần đầu click có trục trặc thì những lần sau vẫn êm xuôi
Vậy nên phần code này không cần phải sửa gì cả
(File ở bài 35 bị lỗi là vì 1 chuyện hoàn toàn khác, đã xử lý xong)
Anh góp ý thì em và mọi người đều cảm ơn (chuyện đương nhiên)
—————————————————-
Ngoài lề một chút:
Em biết là anh đã xem qua topic này vài lần, chắc cũng định bỏ đi rồi nhưng vì thấy thằng em nó sai mà không ai phát hiện nên anh ngứa tay vào đây góp vài lời (em rất cảm ơn về điều này)
Em biết là anh ngại giao tiếp với em nên đã "nói tránh" đi là góp ý cho bài này, bài nọ (không phải bài của em)…
Ẹc… Ẹc… dù là bài nào trong topic này cũng có liên quan đến em thôi
Em khộng ngại mà nói thằng rằng: thời gian gần đây em cũng ngại giao tiếp với anh, vì anh hay nỗi nóng bất thường nên sau này em chẳng khi nào góp ý bất cứ vấn đề gì có liên đến code anh viết (anh thừa hiểu lý do vì sao)
Thôi thì đã lỡ vào đây rồi, có góp ý anh cứ góp ý thẳng (không cần phải "nói tránh" đi đâu). Tính em phân biệt rõ ràng lắm, dù có ghét ai đến mấy nhưng vẫn chịu học hỏi nếu người đó có cái hay… huống chi em với anh dù có "tránh mặt" nhau cũng đâu phải thuộc dạng ghét cay ghét đăng hay thù hằn gì
Anh nghĩ em nói đúng không?
—————————————————-
Ôi… mông lung quá! –=0
Vâng! Có sai chứ anh! Đó là trường hợp anh nói về AlternativeText
Anh cho rằng nên đổi If bMark Then (thay vì If bMark = FALSE Then)
Đó là vì anh cho rằng chuổi trong AlternativeText luôn tồn tại, khi ấy bMark đã = TRUE trước nên phải click lần thứ 2 hình mới được phóng to. Trường hợp này ĐÚNG
Nhưng sao anh chắc rằng chuổi trong AlternativeText luôn tồn tại? Đặt trường hợp mới chèn hình vào, nó rổng thật sự thì nếu sửa code lại như anh góp ý hóa ra cũng lại phải click đến lần thứ 2 ảnh mới được phóng to. Trường hợp này lại SAI
Anh cứ xem video clip sẽ biết: https://www.mediafire.com/download/bibtipaehi6j7ol/test_2.avi
Ở đây, nếu hoàn hảo thì lý ra khi chèn hình ta xử lý xóa chuổi trong AlternativeText luôn mới đúng
(nhưng dù sao chuyện này cũng không quan trọng nên em không nhắc)
Hình như anh chưa hiểu ý em thì phải (cũng như bao lần trước)
Em không giỏi ăn nói nhưng được cái là nghĩ sao nói vậy, lý ra anh phải không nên giận thằng em này mới đúng (nó thật lòng)
Dù sao, nếu vì những lời nói của em mà anh phiền lòng thì em thành thật xin lỗi vậy
Tại anh trai tôi hay nhạy cảm thôi mà. Không có gì đâu!
————————————
Ở trên anh siwtom có 1 gợi ý rất hay về Shapes.AddPicture (cái này quả thật là bây giờ tôi mới biết)
Tôi sẽ cố gắng sưa code theo hướng đi này. Hy vọng có thể giải quyết khó khăn cho bạn
Chờ chút nha…
Đã xong! Code sửa lại khá nhiều
—————
Riêng có đoạn bạn Ngoai Thanh hỏi rằng:
Đó là vì ngoài code trong Module còn có code sự kiện Change, SelectionChange (nằm trong Sheet). Bạn copy ra file khác nhưng quên không mang theo mấy code này nên phần Validation list không hoạt động. Chú ý nha!
Phần sự kiện Change trong file mới tôi cũng cải tiến thêm 1 chút: Cho phép copy hoặc xóa cùng lúc nhiều cell (lúc trước chỉ hoạt động có 1 cell)
Vậy nên, giờ đây nếu:
– Bạn xóa 5 cell ở cột B cùng lúc thì 5 cell tương ứng bên cột A sẽ lập tức bị xóa hình
– Bạn copy đâu đó 5 cell rồi paste vào cột B thì lập tức 5 cell bên cột B được chèn hình (nếu tên hình tồn tại)
Kiểm tra lại giúp tôi xem còn chổ nào trục trặc nữa không?
Khi bạn điều chỉnh kích thước cell xong, chỉ cần click chuột vào 1 cell nào đó là ảnh tự cân chỉnh thôi mà. Tính năng này được thực hiện từ sự kiện SelectionChange:
Có khi nào bạn đã bỏ quên code này không?
Phóng to thì theo tỷ lệ nhưng khi thu nhỏ tôi đâu có viết code để thu nhỏ ngược lại đâu!
Khi thu nhỏ, code chỉnh kích thước hình theo cell mà bạn:
Chổ màu đỏ ấy
Bạn đưa file của bạn lên đây xem thử! Tôi test không phát hiện có gì bất thường cả (kích thước ảnh được điều chỉnh ngon lành cho cả 2 trường hợp load ảnh mới và thay đổi ảnh theo validation)
Trong code này:
Chổ màu đỏ bạn sửa thành
Tức bỏ IF ở đàng trước
Do không có Excel 2003 để test và tôi đoán rằng LockAspectRatio chỉ hoạt động từ Excel 2007 trở lên nên đã IF như vậy
Cứ thử bỏ rồi test lại xem sao nhé
Đúng rồi thày ạ, còn cho hiện tên cùng với ảnh tại list khi load ảnh ngay lần đầu thì sửa code thế nào ạ ?
Quá dễ:
Chổ màu đỏ là mới thêm vào
Cái đó tôi có thấy nhưng chưa tiến hành là vì liên quan đến cái vụ 2003 của bạn đấy!
Bây giờ bạn vui lòng thí nghiệm giùm tôi thế này nhé:
– Mở 1 file Excel trắng
– Chèn 1 vài hình (chèn bằng tay)
– Xong bạn chạy code này thử:
– Kết quả thế nào, báo tôi biết rồi ta tính tiếp
Lưu ý: thí nghiệm trên phải được thực hiện trên Excel 2003 nhé
Ai bảo bạn làm thế nhỉ? Không bao giờ Thầy NDU "trảm" Object mà không có tên tuổi! Bạn mà dùng câu lệnh đó thì vô hình chung nó xóa tất cả các hình trên sheet thì khổ đấy! Trừ khi bạn muốn là thế!
Nếu bạn muốn xóa tất cả thì tôi cũng có một cái thủ tục cho bạn, nó xóa tất Picture, kể cả những Shape!
ActiveSheet.DrawingObjects.Delete
Tuy nhiên, tôi không khuyến khích bạn dùng thủ tục này, bởi một lúc nào đó ta giữ vài hình ảnh lại, LOGO cty chẳng hạn, đã là một chương trình gì đó, bạn không muốn để một vài hình ảnh về bạn sao nhỉ?
Chỉ có thể là dùng vòng lặp thôi! Đặt tên hình cũng rất quan trọng, nếu đặt tên theo địa chỉ ô như Thầy NDU làm thì rất dễ quản lý, muốn xóa cũng rất thuận tiện!
Không biết trên Excel 2003 bạn có thể xóa hình bằng cách này không nhỉ:
Bạn thử insert các picture và đặt tên lần lượt như các tên có màu xanh rồi cho chạy thủ tục đó xem nó có dùng được không, hiện tại tôi đang dùng Excel 2010 nên không test được!
Haha, bạn có biết khi tôi vọc code, tôi đã lưu lại nhiều file không? Hoặc giả tôi vọc tùm lum nhưng khi thoát tôi không lưu lại hoặc save as thành file mới không? Bạn cứ vọc thoải mái sợ quái gì code chứ!
Chẳng sao cả!
Nếu bạn chắc rằng trên bảng tính không có bất cứ HÌNH nào "ngoài luồng" thì chơi được. Ở đây tôi nhắc đến từ HÌNH có nghĩa là Picture, các object khác (như hình vẽ, button…) không được tính
Vậy code thế này:
Sẽ không lo bấm bậy
————–
Trường hợp khác: trên sheet, ngoài hình chèn bằng code còn có những hình khác được chèn bằng tay. Để xóa những hình trước đó đã nạp (tại cột A) thì thay đoạn màu đỏ ở trên bằng code:
Thay vì Select, rồi lại Selection.ClearContents. Bạn có thể gộp lại thành:
Range(, .End(xlDown).Resize(, 1)).ClearContents
Tuy nhiên, dùng End(xlDown) có khi bị "sa bẫy" trong trường hợp cột B có cell rổng ở giữa nha
Thì tôi đang nói đến cái vụ "trừ phi" này nè
Tức là trước khi load ảnh, trên bảng tính đã có ảnh và dữ liệu. Mà dữ liệu cột B lại không liên tục, End(xlDown) sẽ bị "ngắt ngang" giữa chừng —> Ý là vậy đấy
(Tôi làm việc gì, nhất là những việc QUAN TRỌNG rất ghét bị "ngắt ngang" lắm… Ẹc… Ẹc… –=0)
Chổ màu đỏ là thừa nha!
Ngoài ra bạn hãy thí nghiệm cho trường hợp đặc biệt này: Load ảnh khi cột B không có bất cứ dữ liệu nào còn cột A thì có dữ liệu từ A1 đến A4
Bạn sẽ thấy code trên xoá nhầm dữ liệu đấy
Bởi vậy khi viết code tôi rất ghét cái vụ End(xlUp) hoặc End(xlDown) —> Bạn dự trù dữ liệu đến đâu thì cứ xoá đến nấy đi. Đơn giản là Range("A5:B1000").ClearContents mà chơi thôi
Bài này đúng ra đã giải quyết xong nhưng thật lòng tôi vẫn ấm ức. Đánh chết tôi cũng không tin rằng Pictures object không dùng được trên Excel 2003
Mày mò tìm phần mềm Portable 2003 để thử, cuối cùng cũng phát hiện ra nguyên nhân: Trên Excel 2003, code VBA sẽ không làm việc nếu trong tên của Picture có ký tự "$"
Vậy là xong! Chỉ cần đặt lại tên file ảnh không có ký tự chết tiệt này (thay Address bằng Address(0,0) ) là mọi chuyện được giải quyết
Mời thử file
Sở dĩ tôi không chọn SHAPES mà chọn PICTURES vì quan điểm cua tôi là: Luôn gọi Object đúng với KIỂU của nó
Ví dụ:
– Với hình vuông, tôi sẽ dùng Rectangles
– Với đường thằng, tôi sẽ dùng Lines
vân vân… tương tự vậy với Pictures. Mục đích là gọi cái nào ra cái đó, không chơi kiểu gọi chung chung (trừ trường hợp bất khả kháng)
Về tốc độ tôi nghĩ chưa chắc là giống nhau đâu. Bởi SHAPES là nói chung chung cho mọi object (kể cả ActiveX control). Vậy đương nhiên bộ nhớ phân phối cho nó phải lớn hơn so với việc ta phân biệt rõ ràng cái nào thuộc về loại object nào