Calendar и стили

Добрый день!
Пытаюсь поменять стиль календаря, взяла пример из этой темы, но почему-то не срабатывает.
Попробовала добавить border: solid 10px black; в корень .table-bordered {
границы появились. Т.е. на сам календарь стиль добавился, а вот на ячейки дней - нет.

Подскажите, пожалуйста, есть ли где-то список стилей с описанием для календаря, которые можно переопределить. Если списка нет, в первую очередь интересует:

  1. возможность добавить границы между днями,
  2. изменить расположение даты(и, если можно, добавить месяц, т.е. чтобы в ячейке было написано “8 сентября”)
  3. Изменить цвет фона в зависимости от месяца.

Стиль добавляю через setStyleName

Заранее спасибо!

Здравствуйте!

Часто бывает что стили кешируются на странице, попробуйте обновить со сбросом кэша (для windows: CTRL + F5). На версии 7.2.19 стили из приведённой ссылки рабоют.

Как такового списка стилей для компонентов нет. Поэтому как один из способ это смотреть какие CSS классы добавляются элементам в DOM дереве. Смотреть можно в dev tools браузера:
image.

  1. Граница между днями добавляется через стили (как раз те, что приведены в ссылке)
  2. Ниже или по середине расположить не позволяет вёртска, но через CSS свойство text-align можно указать где дата будет находится в пределах одной линии:
    .table-bordered {
      .v-calendar-month .v-calendar-day-number {
        text-align: center;
      }
      ...
    }
    
    К сожалению, добавление текста не предусмотренно компонентом.
  3. Думаю можно подписаться на необходимые события и удалять/добвлять стили в зависимости от свойства startDate календаря. Например, для начальной инициализации можно подписаться на InitEvent, если startDate задан в дескрипторе экрана.
    Поменять фон можно стилем:
    .calendar-september .v-calendar-month td {
      background-color: #ff8a8a;
    }
    

Пишу вот так. Границу вижу, но дата все-равно слева. Пробовала CTRL + F5 - не повлияло. Могу поменять цвет границы, он меняется.
Подскажите, пожалуйста, что не так.

@Subscribe
public void onInit(InitEvent event) {
    setStylePage();
    serviceOrderCalendar.setStyleName("table-bordered");
}

private void setStylePage() {
    Page.Styles styles = Page.getCurrent().getStyles();
    styles.add(".table-bordered {\n" +
            " border: solid 10px blue; \n " +
            ".v-calendar-month .v-calendar-day-number {\n" +
            "    text-align: center;\n" +
            "  }\n" +
            "}");
}

2022-08-31_155628

Дело в том, что Page.Styles#add() добавляет CSS стили, а в приведённых выше примерах и в ссылке используется синтаксис SCSS.

Чтобы применить SCSS из примеров нужно расширить существующую тему приложения, см. Creating a Custom Theme :: Документация Jmix.

Чтобы стили через Page.Styles заработали, нужно писать на чистом CSS:

private void setStylePage() {
    Page.Styles styles = Page.getCurrent().getStyles();
    styles.add(
            ".table-bordered {\n" +
            "    border: solid 10px blue; \n " +
            "} \n" +
            ".table-bordered .v-calendar-month .v-calendar-day-number {\n" +
            "    text-align: center;\n" +
            "}");
}

Роман, спасибо большое! После ваших объяснений стало намного понятнее.
Возникла одна проблема.
Добавляю события на календарь и им присваиваю стили через setStyleName, стили хранятся в файле -ext.scss
Если присваиваю стиль событию SimpleCalendarEvent, то все получается, а если событию EntityCalendarEvent, то получаю NullPointerException. Тот же стиль успешно присвоился событию SimpleCalendarEvent.
Подскажите, пожалуйста, как правильно определить стиль для события EntityCalendarEvent
полный текст ошибки:

java.lang.NullPointerException
at com.haulmont.cuba.core.app.dynamicattributes.DynamicAttributesUtils.isDynamicAttribute(DynamicAttributesUtils.java:80)
at com.haulmont.cuba.core.entity.BaseGenericIdEntity.setValue(BaseGenericIdEntity.java:94)
at com.haulmont.chile.core.model.impl.AbstractInstance.setValue(AbstractInstance.java:142)
at com.haulmont.cuba.gui.components.calendar.EntityCalendarEvent.setStyleName(EntityCalendarEvent.java:118)
at com.elgsys.wld.web.screens.serviceorder.ServiceOrderBrowse.loadServiceOrderToCalendar(ServiceOrderBrowse.java:214)
at com.elgsys.wld.web.screens.serviceorder.ServiceOrderBrowse.onScheduleTypeLookupValueChange(ServiceOrderBrowse.java:183)
at com.haulmont.bali.events.EventHub.publish(EventHub.java:170)
at com.haulmont.cuba.web.gui.components.WebAbstractComponent.publish(WebAbstractComponent.java:100)
at com.haulmont.cuba.web.gui.components.WebAbstractValueComponent.componentValueChanged(WebAbstractValueComponent.java:152)
at com.haulmont.cuba.web.gui.components.WebV8AbstractField.lambda$attachValueChangeListener$ab1c93c8$1(WebV8AbstractField.java:144)
at com.vaadin.ui.ComboBox.lambda$addValueChangeListener$bddd7469$1(ComboBox.java:836)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:709)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:399)
at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:363)
at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1217)
at com.vaadin.ui.AbstractSingleSelect.setSelectedItem(AbstractSingleSelect.java:358)
at com.vaadin.ui.AbstractSingleSelect$1.select(AbstractSingleSelect.java:291)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:153)
at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:115)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocation(ServerRpcHandler.java:442)
at com.vaadin.server.communication.ServerRpcHandler.handleInvocations(ServerRpcHandler.java:407)
at com.vaadin.server.communication.ServerRpcHandler.handleRpc(ServerRpcHandler.java:275)
at com.vaadin.server.communication.UidlRequestHandler.synchronizedHandleRequest(UidlRequestHandler.java:83)
at com.vaadin.server.SynchronizedRequestHandler.handleRequest(SynchronizedRequestHandler.java:40)
at com.vaadin.server.VaadinService.handleRequest(VaadinService.java:1636)
at com.vaadin.server.VaadinServlet.service(VaadinServlet.java:465)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.serviceAppRequest(CubaApplicationServlet.java:329)
at com.haulmont.cuba.web.sys.CubaApplicationServlet.service(CubaApplicationServlet.java:215)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CompositeFilter$VirtualFilterChain.doFilter(CompositeFilter.java:108)
at org.springframework.web.filter.CompositeFilter.doFilter(CompositeFilter.java:74)
at com.haulmont.cuba.web.sys.CubaHttpFilter.doFilter(CubaHttpFilter.java:93)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:835)

Видимо, у EntityCalendarEvent нет свойства styleName?

Eще вот такой вопрос, добавляю события SimpleCalendarEvent в List<CalendarEvent> events
Как корректно добавить events в календарь?

У компонента Calendar есть метод setEventProvider(). В зависимости в каком виде находятся данные: сушность или какой-то POJO объект, можно использовать:

  • ListCalendarEventProvider
  • ContainerCalendarEventProvider

В случае с ContainerCalendarEventProvider можно использовать декларативное объявление в виде:

<data>
    <collection id="eventsDc" ../>
</data>
<layout expand="calendar" spacing="true">
    <calendar id="calendar"
              dataContainer="eventsDc"
              ../>

Чтобы правильно отображались данные из контейнера нужно дполнительно указать какие свойства сущности должны использоваться для атрибутов:

<calendar id="calendar"
          ...
          endDateProperty="my_endDateProperty"
          startDateProperty="my_startDateProperty"/>

Отдельно можно держать в сущности свойство из которого будет браться styleName:

<calendar id="calendar"
          ...
          stylenameProperty="my_styleNameProperty"/>

Программно тоже самое для ContainerCalendarEventProvider можно сделать следующим образом:

ContainerCalendarEventProvider provider = new ContainerCalendarEventProvider(eventsDc);
provider.setEndDateProperty("my_endDateProperty");
provider.setStartDateProperty("my_startDateProperty");
provider.setStyleNameProperty("my_styleNameProperty");

Дополнительно можно почитать: Calendar - Платформа CUBA. Руководство по разработке приложений
Онлайн демо: Sampler::month-calendar

Роман, спасибо за ответ!
У меня есть небольшое уточнение. Я пробовала так сделать - привязать к календарю контейнер, но collection требует привязки какой-то сущности в class. В демо события загружаются из базы, мне же такое не нужно. Я пробовала добавить сущность без аннотации @Table, но при запуске приложения получила ошибку, даже окно логина не загрузилось.
Можно ли как-то решить эту проблему? Не хотелось бы создавать ненужную таблицу в базе.

Добрый день!

Извиние за долгое ожидание. В таком случае можете создать not persistent сущность. В базе данных она храниться не будет, но взаимодействует с различными компонентами и контейнерами данных как обычная сущность. Например, когда создаёте сущность через Studio можно указать тип not persistent.

Или используйте SimpleCalendarEvent и ListCalendarEventProvider

Большое спасибо!