質問者
左クリックした場所に画像を挿入したい

質問
-
お世話になっております。
【OS】
Windows10
【実行したExcelのバージョン】
Office 365 MSO(16.0.12527.20986) 64ビット
【やりたいこと】
コマンドボタン押下→シート上の任意の場所を左クリック→左クリックした場所に画像を挿入
・左クリックする場所は画像や図形の上の可能性もあります
・セルをクリックした場合もセルの左上でなく、クリックした座標が画像の左上に合うように挿入したいです
【やりたいことを実現するために試したこと】
コマンド実行時にループで左クリックを待つようにしました
' Windows API
Private Declare PtrSafe Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As LongPtr) As Long
Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
' クリック座標の構造体
Private Type POINTTYPE
x As Long
y As Long
End Type
' コマンドボタン押下
Public Sub InsertPicture()
' 記号選択時の右クリックを読み飛ばす
GetAsyncKeyState (vbKeyLButton)
'Escキーが押されたらループを抜ける
Do Until GetAsyncKeyState(vbKeyEscape) <> 0
'クリックされたときの処理
If GetAsyncKeyState(vbKeyLButton) <> 0 Then
' 座標取得
Dim point As POINTTYPE
GetCursorPos point
' 画像挿入
Dim path As String
path = "C:\ExcelAddin\images\image1.png"
With ActiveSheet.Pictures.Insert(path)
.Top = point.y
.Left = point.x
End With
Exit Do
End If
Loop
End Sub
【起きている問題】
(1) A1セルの左上あたりをクリックすると、画像の左上がA13セルの中心にくるあたりに表示される
→取得した座標はx=30, y=238でした
(2) シート以外の場所(リボンの余白など)をクリックしても画像が挿入される
【問題解決のために試したこと】
https://okwave.jp/qa/q3709799.html
こちらのサイトを参考にクライアント座標へ変換してみようと試みましたが、うまくいきませんでした
上のコードに以下を追記しました
================================================
' WindowsAPI
Private Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hWnd As Long, lpPoint As point) As Long
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal sClass As String, ByVal sTitle As String) As Long
座標取得の下
' クライアント座標へ変換
Dim hWndForm As Long
hWndForm = FindWindow(vbNullString, "UserForm1")
Dim ret As Boolean
ret = ScreenToClient(hWndForm, point)
================================================
こちらを追記すると関数呼び出し時にエラーになってしまいます
エラーメッセージ
コンパイルエラー:ByRef引数の型が一致しません。
長くなってしまい申し訳ございません。
足りない情報があれば追記いたしますので、お教えいただけると嬉しいです。
よろしくお願いいたします。
すべての返信
-
コンパイルエラー:ByRef引数の型が一致しません。
エラーメッセージの通りです。
ByRef な引数に渡す変数のデータ型が、関数宣言された引数の型と一致していないのが原因ですね。' クリック座標の構造体
Private Type POINTTYPEここでは「POINTTYPE」ユーザー定義型を作成していますが、Declare ステートメントで使用しているのは、「As POINTAPI」や「As point」ですよね。型名が一致していないようです。
Private Declare PtrSafe Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As LongPtr) As Long
GetAsyncKeyState の第1引数は int 型なので、ByVal LongPtr ではなく ByVal Long です。
戻り値は SHORT 型なので、As Long ではなく As Integer です。Private Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
GetCursorPos の宣言ですが、提示されたコードでは POINTAPI という型は宣言されていないようです。
第1引数は LPPOINT 型なので、ByRef POINTTYPE とするべきでしょう。
戻り値は BOOL 型なので、As Long で問題ありません。
Private Declare PtrSafe Function ScreenToClient Lib "user32" (ByVal hWnd As Long, lpPoint As point) As Long
ScreenToClient の宣言ですが、point という型は宣言されていないように思えます。
第1引数は HWND 型なので、As Long ではなく As LongPtr とします。
第2引数は LPPOINT 型なので、GetCursorPos の時と同様、ByRef PONTTYPE にします。
戻り値は BOOL 型なので、As Long で問題ありません。Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal sClass As String, ByVal sTitle As String) As Long
FindWindowA の第1引数と第2引数は LPCSTR 型なので、ByVal String で問題ありません。
戻り値は HWND 型なので、As Long ではなく As LongPtr とします。 -