Тема: Есть ли на VB команда выбора цвета?

Есть ли на VB команда идентичная (acad_colordlg colornum [flag])? Надо в форме VB позволить пользователю выбирать цвет.

Re: Есть ли на VB команда выбора цвета?

по меему только через thisdrawing.setvariable "color",#цвета(от 1до 256). Другого способа не нашел.

Re: Есть ли на VB команда выбора цвета?

В продолжение вопроса...
А есть ли способ присвоить именнваный цвет, например red?

Re: Есть ли на VB команда выбора цвета?

правильно будет не 'color' a 'cecolor'

Re: Есть ли на VB команда выбора цвета?

> Pavelii
Функция

Private Declare Function acedSetColorDialog Lib "acad.exe" (color As Long, ByVal bAllowMetaColor As Boolean, ByVal nCurLayerColor As Long) As Boolean

Пример использования
http://cadhlp.kulichki.com/vba/Samples/acentity.htm

> ssn

Object.Color=1
Object.Color=acRed

Re: Есть ли на VB команда выбора цвета?

Уважаемый Bender откуда у вас такая информация о существовании функции:

acedSetColorDialog

?
Может вы ещё какие-нибудь функции знаете и где найти их список и почитать про них побольше?

Re: Есть ли на VB команда выбора цвета?

> Миша
А вот с того самого сайта.
А где узнать побольше - единственное что могу предложить
https://www.caduser.ru/forum/topic6621.html

Re: Есть ли на VB команда выбора цвета?

bender пишет:

Declare Function acedSetColorDialog Lib "acad.exe"

Браво!
Такие примеры надо приводить в ветках "..vs..", только с другими, недоступными из LISP функциями.

Re: Есть ли на VB команда выбора цвета?

Могу предложить еще несколько функций из библитеки acad.exe - ...ProgressBar... Назначение понятно из названия. Исходный текст с примером http://www.vbdesign.net/expresso/showth … &icp=1. Но может не открываться. Я его не много модифицировал.

Option Explicit
Private Declare Function ProgressMeter Lib "acad.exe" Alias "?acedSetStatusBarProgressMeter@@YAHPBDHH@Z" (ByVal strCaption As String, ByVal intmin As Integer, ByVal intmax As Integer) As Boolean
Private Declare Function SetProgBarPos Lib "acad.exe" Alias "?acedSetStatusBarProgressMeterPos@@YAHH@Z" (ByVal intVal As Integer) As Boolean
Private Declare Function RestoreStatus Lib "acad.exe" Alias "?acedRestoreStatusBar@@YAXXZ" () As Boolean
Private Sub progressBarOn(ByVal captionProgressBar As String, ByVal minProgressBar As Integer, ByVal maxProgressBar As Integer)
On Error Resume Next
ProgressMeter captionProgressBar, minProgressBar, maxProgressBar
End Sub
Private Sub progressBarOff()
On Error Resume Next
RestoreStatus
End Sub
Private Sub progressBarRun(ByVal i As Integer)
On Error Resume Next
SetProgBarPos (i)
End Sub
Public Sub TestProgressBar()
Dim objEnt As AcadEntity
Dim i As Integer
progressBarOn "Примитивы пространста модели", 0, ThisDrawing.ModelSpace.Count
For Each objEnt In ThisDrawing.ModelSpace
    i = i + 1
    progressBarRun i
Next
progressBarOff
End Sub

Re: Есть ли на VB команда выбора цвета?

Решил воспользоваться данной функцией, но никак не пойму где ошибка
в приведённом ниже коде. Если кто знает помогите пожалуйсто.
Диалоговое окно грузится как положено, но при выходе из него,
хоть по Ok, хоть по Cancel даёт ошибку:
"Bad DLL calling convention (Error 49)"

Private Declare Function acedSetColorDialog Lib "acad.exe" _
  (color As Long, ByVal bAllowMetaColor As Boolean, ByVal nCurLayerColor As Long) As Boolean
Sub ColorDlg()
Dim AllowMetaColor As Boolean, Res As Boolean
Dim DefColor As Long, NewColor As Long
   NewColor = 7
   bAllowMetaColor = True
   DefColor = 7
   Res = acedSetColorDialog(NewColor, AllowMetaColor, DefColor)
End Sub

И ещё, ни кто случайно не знает, как работать с аналогичной функцией:

acedSetColorDialogTrueColor

А то Lisp код (acad_truecolordlg (420 . 1005220)) через командую строку
не отрабатывает пока макрос не завершит работу, поэтому приходится макрос
бить на две части и прехватывать изменение системной переменной "USERS1".

Re: Есть ли на VB команда выбора цвета?

Можно воспользоваться  API.
http://www.mvps.org/access/api/api0060.htm

Re: Есть ли на VB команда выбора цвета?

> Gogi

Private Declare Function CHOOSECOLOR Lib "comdlg32.dll" Alias "ChooseColorA" (pChoosecolor As CHOOSECOLOR) As Long

При помощи этого мы задействуем системную палитру цветов, значение которое она нам вернет не будет значением ACI, это означает что мы не сможем воспользоваться связкой

AnyObj.Color = cc.rgbResult

Re: Есть ли на VB команда выбора цвета?

> Gogi
Спасибо за ссылку, интересно покапаться.
Однако SmeL прав, работая в AutoCAD необходима возможность работать
в его цветовых системах, с их возможностями.
" AnyObj.Color = cc.rgbResult "
Хочу уточнить, с данной связкой как раз проблем нет. Начиная с AutoCAD 2004
для задания цвета используется объект:
AnyObj.TrueColor
и в нём есть метод SetRGB. Метод Color оставлен временно, только для
совместимости со старыми приложениями.

Re: Есть ли на VB команда выбора цвета?

> bender
Выше приведённая декларация функции acedSetColorDialog возможно работала
в AutoCAD версий с 2000 по 2002.
Начиная с AutoCAD версии 2004, всё изменилось. Данная функция больше не используется.
Однако, ею всё ещё можно воспользоваться, ниже приведён код работы с ней.

Private Declare Function acedSetColorDialog Lib "acad.exe" _
  (Color As acColor, ByVal AllowMetaColor As Byte) As Byte
'   Color - передаёт значение по умолчанию и принимает новое;
'   AllowMetaColor - определяет активность кнопок ByLayer и ByBlock:
'                            0 - не активны;
'                            1 - активны.
Sub DlgColorACI()
Dim Color As acColor, ColorOld As acColor
Dim AllowMetaColor As Byte, Result As Byte
   Color = acByLayer
   AllowMetaColor = 1
   On Error Resume Next
   ColorOld = Color
   Result = acedSetColorDialog(Color, AllowMetaColor)
   On Error GoTo 0
   If Color = ColorOld Then
      MsgBox "Выбор был отменён!", vbExclamation
    Else
      MsgBox "Вы выбрали: " & Color & " цвет!", vbInformation
   End If
End Sub

При выходе из функции по идее должна передать:
0 - при отмене выбора;
1 - если цвет был выбран.
На самом деле на выходе передаёт ошибку.
Возможная причина будет описана в конце, при описании новой функции.
Но, как я выше сказал, данная функция больше не используется, поэтому и нет
смысла с нею связываться.
За диалоговое окно выбора цвета отвечает Dll-библиотека Color.dll, само
диалоговое окно расположено в ресурсной библиотеке ColorRes.dll.
Например Lisp функция acad_colordlg вызывает через Arx-модуль AcApp.arx
функцию DoColorDialog напрямую из Color.dll. Поэтому думаю следует идти тем же путём.
Ниже приведён код работы с данной функцией.

Private Declare Function DoColorDialog Lib "color.dll" _
  (ByVal NotUsed As Long, ByVal ColorCurrent As acColor, ByVal NotUsed As Long, _
  ByVal NotUsed As Long, ByVal AllowMetaColor As Byte) As acColor
'   ColorCurrent - передаёт значение по умолчанию;
'   AllowMetaColor - определяет активность кнопок ByLayer и ByBlock:
'                            0 - не активны;
'                            1 - активны.
'   Возвращает:
'              -1 - при отмене выбора;
'              0-256 - выбранный цвет.
Sub DlgColorACI()
Dim Color As acColor, ColorCurrent As acColor
Dim AllowMetaColor As Byte
   ColorCurrent = 125
   AllowMetaColor = 1
   Color = DoColorDialog(0, ColorCurrent, 0, 0, AllowMetaColor)
   If Color = -1 Then
      MsgBox "Выбор был отменён!", vbExclamation
    Else
      MsgBox "Вы выбрали: " & Color & " цвет!", vbInformation
   End If
End Sub

Для работы со всеми цветавыми системами AutoCAD, используется функция:
acedSetColorDialogTrueColor из acad.exe или DoColorDialogTrueColor из color.dll
Однако с функцией DoColorDialogTrueColor на прямую, связываться не советую.
Тип Boolean не желательно использовать при работе с данными функциями, т. к. в
VBA в отличии от остальных языков, он имеет 2 байта: True=1 и False=-1.
Ниже приведён код работы с функцией acedSetColorDialogTrueColor.

Type tColor
   NotKnow As Long
   Color As Long
   ColorName As Long
   ColorBook As Long
End Type
Private Declare Function acedSetColorDialogTrueColor Lib "acad.exe" _
  (Color As tColor, ByVal AllowMetaColor As Byte, _
   ColorCurrent As tColor, ByVal ColorSystems As Byte) As Byte
'   Color - передаёт значение по умолчанию и принимает новое;
'   AllowMetaColor - определяет активность кнопок ByLayer и ByBlock:
'                       0 - не активны;
'                       1 - активны;
'   ColorCurrent - не используется, но обязано быть определено, возможно было
'                  задекларировано на будущее, для передачи цвета по умолчанию;
'   ColorSystems - определяет набор отображаемых вкладок с цветавыми системами:
'                     1 - ACI;
'                     2 - RGB;
'                     4 - BookName;
'                  Сумма данных значений даёт требуемый набор:
'                     1+2=3   - ACI+RGB;
'                     1+4=5   - ACI+BookName;
'                     2+4=6   - RGB+BookName;
'                     1+2+4=7 - ACI+RGB+BookName.
'
Sub DlgTrueColor()
Dim Color As AcadAcCmColor
Dim AllowMetaColor As Byte, ColorSystems As Byte, Result As Byte
Dim ColorOld As Long
Dim ColorLong As tColor, ColorCurrent As tColor ' При переносе данной строки из конца в другое место и выборе именованого цвета AutoCAD вылетает.
   With ColorLong
      .NotKnow = 1691390208 ' В необходимости данного параметра разобраться не смог, видимо какой-то адресс, поэтому просто передаём данное значение.
      .Color = -1024366560  ' Значение цвета по умолчанию в формате AcCmEntityColor или AcadEntityObj.TrueColor.EntityColor
      .ColorName = 0        ' Адрес по каторому располагается имя цвета.
      .ColorBook = 0        ' Адрес по которому располагается имя библиотеки цвета.
   End With
   With ColorCurrent
      .NotKnow = 1691390208
      .Color = -1023410169
      .ColorName = 0
      .ColorBook = 0
   End With
   AllowMetaColor = 1
   ColorSystems = 7
   On Error Resume Next
   ColorOld = ColorLong.Color
   Result = acedSetColorDialogTrueColor(ColorLong, AllowMetaColor, ColorCurrent, ColorSystems)
   On Error GoTo 0
   If ColorLong.Color = ColorOld Then
      MsgBox "Выбор был отменён!", vbExclamation
    Else
      Set Color = Application.GetInterfaceObject("AutoCAD.AcCmColor.16")
      Color.EntityColor = ColorLong.Color
      If Color.ColorMethod = acColorMethodByRGB Then
         MsgBox "Вы выбрали: " & Chr(13) & Chr(10) & _
           "   цветовая система: RGB - " & Color.ColorMethod & Chr(13) & Chr(10) & _
           "   цвет: R" & Color.Red & ":G" & Color.Green & ":B" & Color.Blue, vbInformation
       Else
         MsgBox "Вы выбрали: " & Chr(13) & Chr(10) & _
           "   цветовая система: ACI - " & Color.ColorMethod & Chr(13) & Chr(10) & _
           "   цвет: " & Color.ColorIndex, vbInformation
      End If
   End If
End Sub

При выходе из функции по идее должна передать:
0 - при отмене выбора;
1 - если цвет был выбран.
На самом деле на выходе передаёт ошибку.
Данная проблема по всей видимости в следующем: данная функция не предназначена для
внешнего использования. Поэтому в ней нет, на выходе, обнуления флага ошибки.
Определение же цветовой системы и выбранного цвета осуществляется как раз по
соответствующей ошибке. То есть, обрабатывается имя цвета и если возникла ошибка
идёт переход на обработку цвета TrueColor, если возникла ошибка идёт переход на
обработку цвета ACI. Сами же разработчики на них не обращают внимания, например
при выборе цвета в диалоговом окне команды TABLE из модуля AcTabll.arx идут сплошные ошибки.
Но есть и более серьёзная проблема при использовании данной функции.
Если я не ошибаюсь, AutoCAD пишется на Assembler и поэтому многие параметры во внутренних
функциях передаются через адреса.
В данной функции через адрес передаются имена цвета и библиотеки цвета. Поэтому на
VBA нет возможности ни передать значение именованного цвета, ни получить имя выбранного
цвета в именованной системе. Назад мы получаем только адреса, где расположены данные имена.
Возможно знатоки API функций знают какие нибудь функции в Windows, с помощью которых
можно по полученным адресам считать возвращённые имена. Если знаете надеюсь поделитесь.
У разработчиков Arx приложений таких проблем нет, они могут просто вставить код
на Assembler и без проблем считать любую информацию откуда угодно. В VBA для приложений
ни каких подобных возможностей просто нет. Поэтому передать и получить мы можем только
RGB значение именованного цвета.
Ниже приводятся несколько процедур по работе со значениями цвета.
Цвет хранится в шестнадцатеричном формате:
C2010203
С2 - номер цветовой системы AutoCAD
01 - Красный цвет в RGB и 00 в ACI, ByLayer, ByBlock
02 - Зелёный цвет в RGB и 00 в ACI, ByLayer, ByBlock
03 - Синий цвет в RGB и значение цвета в ACI, 00 в ByLayer и ByBlock
Цвет, в стандартной системе Windows, имеет другой порядок
00030201
01 - Красный
02 - Зелёный
03 - Синий
Данная процедура получает значение цвета напрямую из шестнадцатеричного кода цвета.
Особого смысла в ниже приведённой процедуре нет, дана просто для наглядности.

Sub HexToColor()
Dim ColorMethod As Byte, ColorIndex As Byte
Dim Red As Byte, Green As Byte, Blue As Byte
Dim ColorHex As String
   ColorHex = "C2F16820"
   ColorMethod = Val("&H" & Left(ColorHex, 2))
   Select Case ColorMethod
    Case 192: ColorIndex = 256               ' ByLayer
    Case 193: ColorIndex = 0                 ' ByBlock
    Case 194                                 ' ByRGB
      Red = Val("&H" & Mid(ColorHex, 3, 2))
      Green = Val("&H" & Mid(ColorHex, 5, 2))
      Blue = Val("&H" & Right(ColorHex, 2))
    Case 195                                 ' ByACI
      ColorIndex = Val("&H" & Right(ColorHex, 2))
    Case 197                                 ' Foreground
   End Select
End Sub

Ниже приведённая процедура делает в принципе тоже, что и предыдущая.
Получает значение цвета из формата AcCmEntityColor.

Sub EntityColorToColor()
Dim ColorMethod As Byte, ColorIndex As acColor
Dim Red As Byte, Green As Byte, Blue As Byte
Dim ColorLong As Long
   ColorLong = -1024366560
   ColorMethod = (ColorLong And &H7F000000) \ &H1000000
   If ColorLong < 0 Then ColorMethod = ColorMethod Or &H80
   Select Case ColorMethod
    Case acColorMethodByLayer: ColorIndex = 256
    Case acColorMethodByBlock: ColorIndex = 0
    Case acColorMethodByRGB
      Red = (ColorLong And &HFF0000) \ &H10000
      Green = (ColorLong And &HFF00&) \ &H100&
      Blue = ColorLong And &HFF&
    Case acColorMethodByACI
      ColorIndex = ColorLong And &HFF&
    Case acColorMethodForeground
   End Select
End Sub

Ниже приведённая процедура переводит значение цвета в формат AcCmEntityColor.

Sub ColorToHex()
Dim ColorMethod As AcColorMethod
Dim ColorIndex As acColor
Dim Red As Byte, Green As Byte, Blue As Byte
Dim EntityColor As Long
Dim ColorHex As String
   ColorMethod = acColorMethodByRGB
   If ColorMethod = acColorMethodByRGB Then
      Red = 241
      Green = 104
      Blue = 32
      ColorHex = Hex(ColorMethod) & Hex(Red) & Hex(Green) & Hex(Blue)
    ElseIf ColorMethod = acColorMethodByACI Then
      ColorIndex = acYellow
      ColorHex = Hex(ColorMethod) & "0000" & Hex(ColorIndex)
    Else
      ColorHex = Hex(ColorMethod) & "000000"
   End If
   EntityColor = Val("&H" & ColorHex)
End Sub

Re: Есть ли на VB команда выбора цвета?

До полной коллекции:
Процедура перевода значения цвета стандартного Windows в формат AcCmEntityColor

Sub winRGBToacRGB()
Dim winRGB as Long, acRGB as Long
   winRGB = RGB(241, 104, 32)
   acRGB = Val("&HC2" & Hex(winRGB And &HFF&) & Hex((winRGB And &HFF00&) \ &H100&) & _
     Hex((winRGB And &HFF0000) \ &H10000))
' или
   acRGB = Val("&H" & Hex(acColorMethodByRGB) & Hex(winRGB And &HFF&) & _
     Hex((winRGB And &HFF00&) \ &H100&) & Hex((winRGB And &HFF0000) \ &H10000))
End Sub

Процедура перевода значения цвета из формата AcCmEntityColor в стандартный Windows

Sub acRGBTowinRGB()
Dim winRGB as Long, acRGB as Long
   acRGB = -1024366560
   winRGB = Val("&H" & Hex(acRGB And &HFF&) & Hex((acRGB And &HFF00&) \ &H100&) & _
     Hex((acRGB And &HFF0000) \ &H10000))
End Sub

Re: Есть ли на VB команда выбора цвета?

Прошу прощения, в выше приведённых примерах, при использовании функции Hex(), не учёл, что данная функция откидывает старший (левый) полубайт, если он равен нулю.
Поэтому правильная запись, во всех приведённых примерах использующих функцыю Hex(), будет выглядеть так:

Format(Hex(), "#00")

И кроме того, в одном из выше приведённых примеров, я задекларировал и определил объект Color следующим методом:

Dim Color As AcadAcCmColor
   Set Color = Application.GetInterfaceObject("AutoCAD.AcCmColor.16")

Желательно так не делать, иначе вы привязываете свой код к конкретной версии AutoCAD.
Лучше использовать следующий метод:

Dim Color As New AcadAcCmColor